Skip to content

Commit

Permalink
Improve error reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
Carlos Wu Fei authored and Carlos Wu Fei committed Oct 22, 2023
1 parent 7866a9b commit b0bc579
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 67 deletions.
33 changes: 23 additions & 10 deletions api/bots/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
from fastapi.exceptions import RequestValidationError

from account.account import Account
from deals.margin import MarginShortError
from deals.controllers import CreateDealController
from tools.enum_definitions import BinbotEnums
from tools.exceptions import OpenDealError, NotEnoughFunds, QuantityTooLow, IsolateBalanceError
from tools.exceptions import BinanceErrors, BinbotErrors, QuantityTooLow
from tools.handle_error import (
handle_binance_errors,
json_response,
Expand Down Expand Up @@ -184,14 +183,11 @@ def activate(self, botId: str):
bot, db_collection=self.db_collection.name
).open_deal()
return json_response_message("Successfully activated bot!")
except OpenDealError as error:
return json_response_error(error.args[0])
except NotEnoughFunds as e:
return json_response_error(e.args[0])
except MarginShortError as error:
message = str("Unable to create margin_short bot: ".join(error.args))
return json_response_error(message)
except IsolateBalanceError as error:
except BinanceErrors as error:
self.post_errors_by_id(botId, error.message)
return json_response_error(error.message)
except BinbotErrors as error:
self.post_errors_by_id(botId, error.message)
return json_response_error(error.message)
except Exception as error:
resp = json_response_error(f"Unable to activate bot: {error}")
Expand Down Expand Up @@ -355,3 +351,20 @@ def put_archive(self, botId):
resp = json_response({"message": f"Failed to archive bot {error}"})

return resp

def post_errors_by_id(self, bot_id: str, reported_error: str):
"""
Directly post errors to Bot
which should show in the BotForm page in Web
"""
try:
self.db_collection.update_one(
{"id": bot_id}, {"$push": {"errors": reported_error}}
)
return json_response(
{"message": "Successfully submitted bot errors", "botId": bot_id}
)
except Exception as error:
resp = json_response({"message": f"Failed to submit bot errors: {error}"})

return resp
5 changes: 5 additions & 0 deletions api/bots/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,8 @@ def deactivate(id: str):
@bot_blueprint.put("/bot/archive/{id}", tags=["bots"])
def archive(id: str):
return Bot(collection_name="bots").put_archive(id)


@bot_blueprint.post("/bot/errors/{bot_id}", tags=["bots"])
def bot_errors(bot_id: str, bot_errors: str):
return Bot(collection_name="bots").post_errors_by_id(bot_id, bot_errors)
12 changes: 9 additions & 3 deletions api/bots/schemas.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from time import time
from typing import Literal
from typing import List, Literal

from bson.objectid import ObjectId
from tools.enum_definitions import Status
Expand Down Expand Up @@ -40,7 +40,7 @@ class BotSchema(BaseModel):
created_at: float = time() * 1000
deal: DealSchema = Field(default_factory=DealSchema)
dynamic_trailling: bool = False
errors: list[str] = []
errors: list[str] = [] # Event logs
locked_so_funds: float = 0 # funds locked by Safety orders
mode: str = "manual" # Manual is triggered by the terminal dashboard, autotrade by research app
name: str = "Default bot"
Expand Down Expand Up @@ -90,12 +90,18 @@ def check_trailling(cls, v: str | bool):
return False
return True

@validator("errors")
def check_errors_format(cls, v: list[str]):
if isinstance(v, list):
return []
return []

class Config:
use_enum_values = True
arbitrary_types_allowed = True
json_encoders = {ObjectId: str}
schema_extra = {
"description": "Most fields are optional. Deal field is generated internally, orders are filled up by Binance and",
"description": "Most fields are optional. Deal field is generated internally, orders are filled up by Binance",
"example": {
"pair": "BNBUSDT",
"balance_size_to_use": 0,
Expand Down
25 changes: 14 additions & 11 deletions api/deals/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from pymongo import ReturnDocument
from tools.enum_definitions import Status
from tools.exceptions import (
ShortStrategyError,
TakeProfitError,
)
from tools.handle_error import (
Expand Down Expand Up @@ -90,7 +89,11 @@ def base_order(self):
pair, supress_notation(price, self.price_precision), qty, "BUY"
)
else:
res = self.buy_order(symbol=pair, qty=qty, price=supress_notation(price, self.price_precision))
res = self.buy_order(
symbol=pair,
qty=qty,
price=supress_notation(price, self.price_precision),
)

order_data = OrderSchema(
timestamp=res["transactTime"],
Expand Down Expand Up @@ -280,7 +283,11 @@ def update_take_profit(self, order_id):
print("Old take profit order cancelled")

qty = round_numbers(self.get_one_balance(asset), self.qty_precision)
res = self.sell_order(symbol=self.active_bot.pair, qty=qty, price=supress_notation(new_tp_price, self.price_precision))
res = self.sell_order(
symbol=self.active_bot.pair,
qty=qty,
price=supress_notation(new_tp_price, self.price_precision),
)

# New take profit order successfully created
order = handle_binance_errors(res)
Expand Down Expand Up @@ -320,7 +327,6 @@ def update_take_profit(self, order_id):
else:
self.update_deal_logs("Error: Bot does not contain a base order deal")


def open_deal(self):
"""
Mandatory deals section
Expand Down Expand Up @@ -382,13 +388,10 @@ def open_deal(self):

# Keep trailling_stop_loss_price up to date in case of failure to update in autotrade
# if we don't do this, the trailling stop loss will trigger
if (
self.active_bot.deal
and (
self.active_bot.deal.trailling_stop_loss_price > 0
or self.active_bot.deal.trailling_stop_loss_price
< self.active_bot.deal.buy_price
)
if self.active_bot.deal and (
self.active_bot.deal.trailling_stop_loss_price > 0
or self.active_bot.deal.trailling_stop_loss_price
< self.active_bot.deal.buy_price
):
take_profit_price = float(self.active_bot.deal.buy_price) * (
1 + (float(self.active_bot.take_profit) / 100)
Expand Down
66 changes: 31 additions & 35 deletions api/deals/margin.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,13 @@ def init_margin_short(self, initial_price):
self.qty_precision,
)

# transfer quantity is base order size (what we want to invest) + stop loss to cover losses
stop_loss_price_inc = float(initial_price) * (
1 + (self.active_bot.stop_loss / 100)
)
final_qty = float(stop_loss_price_inc * qty)
transfer_qty = round_numbers_ceiling(
float(qty),
final_qty,
self.qty_precision,
)

Expand Down Expand Up @@ -185,41 +190,32 @@ def init_margin_short(self, initial_price):
raise MarginShortError("Isolated margin not available")

asset = self.active_bot.pair.replace(self.active_bot.balance_to_use, "")
try:
self.create_margin_loan(
asset=asset, symbol=self.active_bot.pair, amount=qty
)
loan_details = self.get_margin_loan_details(
asset=asset, isolatedSymbol=self.active_bot.pair
)
self.create_margin_loan(
asset=asset, symbol=self.active_bot.pair, amount=qty
)
loan_details = self.get_margin_loan_details(
asset=asset, isolatedSymbol=self.active_bot.pair
)

self.active_bot.deal.margin_short_loan_timestamp = loan_details["rows"][0][
"timestamp"
]
self.active_bot.deal.margin_short_loan_principal = loan_details["rows"][0][
"principal"
]
self.active_bot.deal.margin_loan_id = loan_details["rows"][0]["txId"]
self.active_bot.deal.margin_short_base_order = qty

# Estimate interest to add to total cost
asset = self.active_bot.pair.replace(self.active_bot.balance_to_use, "")
# This interest rate is much more accurate than any of the others
hourly_fees = self.signed_request(
url=self.isolated_hourly_interest,
payload={"assets": asset, "isIsolated": "TRUE"},
)
self.active_bot.deal.hourly_interest_rate = float(
hourly_fees[0]["nextHourlyInterestRate"]
)
self.active_bot.deal.margin_short_loan_timestamp = loan_details["rows"][0][
"timestamp"
]
self.active_bot.deal.margin_short_loan_principal = loan_details["rows"][0][
"principal"
]
self.active_bot.deal.margin_loan_id = loan_details["rows"][0]["txId"]
self.active_bot.deal.margin_short_base_order = qty

except BinanceErrors as error:
if error.args[1] == -3045:
self._append_errors(error.message)
self.terminate_failed_transactions()
raise MarginShortError(error.message)
except Exception as error:
logging.error(error)
# Estimate interest to add to total cost
asset = self.active_bot.pair.replace(self.active_bot.balance_to_use, "")
# This interest rate is much more accurate than any of the others
hourly_fees = self.signed_request(
url=self.isolated_hourly_interest,
payload={"assets": asset, "isIsolated": "TRUE"},
)
self.active_bot.deal.hourly_interest_rate = float(
hourly_fees[0]["nextHourlyInterestRate"]
)

return

Expand Down Expand Up @@ -389,7 +385,7 @@ def margin_short_base_order(self):
self.init_margin_short(initial_price)
order_res = self.sell_margin_order(
symbol=self.active_bot.pair,
qty=self.active_bot.deal.margin_short_base_order,
qty=self.active_bot.base_order_size,
)
else:
# Simulate Margin sell
Expand Down
6 changes: 3 additions & 3 deletions web/src/components/LogsInfo.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React from "react";
import { Card, CardBody, CardHeader, CardTitle } from "reactstrap";

export default function LogInfo({ info }) {
export default function LogInfo({ events }) {
return (
<Card>
<CardHeader>
<CardTitle tag="h5">Logs</CardTitle>
<CardTitle tag="h5">Event logs</CardTitle>
</CardHeader>
<CardBody>
{info.map((item, i) => (
{events.map((item, i) => (
<div key={i}>
<p>{item}</p>
<hr />
Expand Down
9 changes: 4 additions & 5 deletions web/src/pages/bots/BotForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -555,11 +555,7 @@ class BotForm extends React.Component {
<Col md="7" sm="12">
<BotInfo bot={this.props.bot} />
</Col>
{this.props.bot.errors.length > 0 && (
<Col md="4" sm="12">
<LogsInfo info={this.props.bot.errors} />
</Col>
)}

</>
) : (
""
Expand Down Expand Up @@ -754,6 +750,9 @@ class BotForm extends React.Component {
{this.props.balance_estimate && (
<BalanceAnalysis balance={this.props.balance_estimate} />
)}
{this.props.bot.errors.length > 0 && (
<LogsInfo events={this.props.bot.errors} />
)}
</Col>
</Row>
</Form>
Expand Down
1 change: 1 addition & 0 deletions web/src/state/bots/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const bot = {
baseOrderSizeError: false,
balance_to_use: "USDT",
bot_profit: 0,
errors: [],
mode: "manual",
max_so_count: "0",
maxSOCountError: false,
Expand Down

0 comments on commit b0bc579

Please sign in to comment.