Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/account/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ def matching_engine(self, symbol: str, order_side: bool, qty: float = 0) -> floa
so that order can immediately buy/sell
If it doesn't match, do split order
@param: order_side -
Buy order = get bid prices = True
Sell order = get ask prices = False
Buy order = get bid prices = False
Sell order = get ask prices = True
@param: base_order_size - quantity wanted to be bought/sold in fiat (USDC at time of writing)
"""
data = self.get_book_depth(symbol)
Expand Down
17 changes: 6 additions & 11 deletions api/apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ class BinanceApi:
isolated_fee_url = f"{BASE}/sapi/v1/margin/isolatedMarginData"
isolated_account_url = f"{BASE}/sapi/v1/margin/isolated/account"
margin_isolated_transfer_url = f"{BASE}/sapi/v1/margin/isolated/transfer"
loan_record_url = f"{BASE}/sapi/v1/margin/loan"
margin_repay_url = f"{BASE}/sapi/v1/margin/repay"
loan_record_url = f"{BASE}/sapi/v1/margin/borrow-repay"
isolated_hourly_interest = f"{BASE}/sapi/v1/margin/next-hourly-interest-rate"
margin_order = f"{BASE}/sapi/v1/margin/order"
max_borrow_url = f"{BASE}/sapi/v1/margin/maxBorrowable"
Expand Down Expand Up @@ -267,6 +266,7 @@ def create_margin_loan(self, asset, symbol, amount, isIsolated=True):
"symbol": symbol,
"amount": amount,
"isIsolated": isIsolated,
"type": "BORROW",
},
)

Expand All @@ -276,29 +276,24 @@ def get_max_borrow(self, asset, isolated_symbol: str | None = None):
payload={"asset": asset, "isolatedSymbol": isolated_symbol},
)

def get_margin_loan_details(self, asset: str, isolatedSymbol: str):
def get_margin_loan_details(self, loan_id: int):
return self.signed_request(
self.loan_record_url,
payload={"asset": asset, "isolatedSymbol": isolatedSymbol},
)

def get_margin_repay_details(self, asset: str, isolatedSymbol: str):
return self.signed_request(
self.margin_repay_url,
payload={"asset": asset, "isolatedSymbol": isolatedSymbol},
payload={"txId": loan_id},
)

def repay_margin_loan(
self, asset: str, symbol: str, amount: float | int, isIsolated: str
):
return self.signed_request(
self.margin_repay_url,
self.loan_record_url,
method="POST",
payload={
"asset": asset,
"symbol": symbol,
"amount": amount,
"isIsolated": isIsolated,
"type": "REPAY",
},
)

Expand Down
4 changes: 1 addition & 3 deletions api/bots/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ class BotBase(BaseModel):
)
trailling_profit: Amount = Field(default=0, ge=-1, le=101)
strategy: Strategy = Field(default=Strategy.long)
total_commission: float = Field(
default=0, description="autoswitch to short_strategy"
)


class BotModel(BotBase):
"""
Expand Down
14 changes: 12 additions & 2 deletions api/bots/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ def get_one_by_id(id: str, session: Session = Depends(get_session)):
}
except ValidationError as error:
return BotResponse(message="Bot not found.", error=1, data=error.json())
except ValueError as error:
return BotResponse(message="Bot not found.", error=1, data=str(error))


@bot_blueprint.get("/bot/symbol/{symbol}", tags=["bots"])
Expand All @@ -95,7 +97,8 @@ def get_one_by_symbol(symbol: str, session: Session = Depends(get_session)):
return BotResponse(message="Successfully found one bot.", data=data)
except ValidationError as error:
return BotResponse(message="Bot not found.", error=1, data=error.json())

except ValueError as error:
return BotResponse(message="Bot not found.", error=1, data=str(error))

@bot_blueprint.post("/bot", tags=["bots"], response_model=BotResponse)
def create(
Expand All @@ -117,7 +120,6 @@ def edit(
session: Session = Depends(get_session),
):
try:

controller = BotTableCrud(session=session)
bot_table = controller.get_one(id)
bot_table.sqlmodel_update(bot_item)
Expand All @@ -136,6 +138,8 @@ def edit(
return BotResponse(message=f"Failed to edit bot: {error.json()}", error=1)
except BinbotErrors as error:
return BotResponse(message=error.message, error=1)
except ValueError as error:
return BotResponse(message="Bot not found.", error=1, data=str(error))


@bot_blueprint.delete("/bot", response_model=IResponseBase, tags=["bots"])
Expand Down Expand Up @@ -182,6 +186,8 @@ def activate_by_id(id: str, session: Session = Depends(get_session)):
except BinanceErrors as error:
deal_instance.controller.update_logs(bot_id=id, log_message=error.message)
return BotResponse(message=error.message, error=1)
except ValueError as error:
return BotResponse(message="Bot not found.", error=1, data=str(error))


@bot_blueprint.delete("/bot/deactivate/{id}", response_model=BotResponse, tags=["bots"])
Expand Down Expand Up @@ -209,6 +215,8 @@ def deactivation(id: str, session: Session = Depends(get_session)):
}
except BinbotErrors as error:
return BotResponse(message=error.message, error=1)
except ValueError as error:
return BotResponse(message="Bot not found.", error=1, data=str(error))


@bot_blueprint.post("/bot/errors/{bot_id}", response_model=BotResponse, tags=["bots"])
Expand All @@ -231,3 +239,5 @@ def bot_errors(
return BotResponse(message="Errors posted successfully.", data=response_data)
except ValidationError as error:
return BotResponse(message="Failed to post errors", data=error.json(), error=1)
except ValueError as error:
return BotResponse(message="Bot not found.", error=1, data=str(error))
14 changes: 6 additions & 8 deletions api/database/api_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,12 @@ def create_dummy_bot(self):
total_commission=0,
)
deal = DealTable(
buy_price=1.7777,
buy_total_qty=12,
buy_timestamp=0,
opening_price=1.7777,
opening_qty=12,
opening_timestamp=0,
current_price=0,
sd=0,
avg_buy_price=0,
avg_opening_price=0,
take_profit_price=2.3,
sell_timestamp=0,
sell_price=0,
Expand All @@ -160,9 +160,7 @@ def create_dummy_bot(self):
trailling_profit_price=0,
stop_loss_price=0,
trailling_profit=0,
original_buy_price=0,
short_sell_price=0,
margin_short_loan_principal=0,
margin_loan_id=0,
hourly_interest_rate=0,
margin_short_sell_price=0,
Expand Down Expand Up @@ -192,7 +190,7 @@ def create_dummy_bot(self):
trailling_deviation=0.63,
trailling_profit=2.3,
strategy=Strategy.long,
short_buy_price=0,
short_opening_price=0,
short_sell_price=0,
total_commission=0,
)
Expand All @@ -214,7 +212,7 @@ def create_dummy_bot(self):
trailling_deviation=0.63,
trailling_profit=2.3,
strategy=Strategy.long,
short_buy_price=0,
short_opening_price=0,
short_sell_price=0,
total_commission=0,
)
Expand Down
2 changes: 1 addition & 1 deletion api/database/bot_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ def update_order(
"""

initial_bot = self.get_one(bot_id=str(order.bot_id))
initial_bot.total_commission += commission
initial_bot.deal.total_commissions += commission
initial_bot.logs.append("Order status updated")

self.session.add(order)
Expand Down
7 changes: 2 additions & 5 deletions api/database/models/bot_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,17 @@ class BotTable(SQLModel, table=True):
)
trailling_profit: float = Field(default=0)
strategy: Strategy = Field(default=Strategy.long, sa_column=Column(Enum(Strategy)))
total_commission: float = Field(
default=0, description="autoswitch to short_strategy"
)

# Table relationships filled up internally
orders: list[ExchangeOrderTable] = Relationship(
back_populates="bot",
sa_relationship_kwargs={"lazy": "joined"},
sa_relationship_kwargs={"lazy": "joined", "single_parent": True},
)
deal_id: Optional[UUID] = Field(
default=None, foreign_key="deal.id", ondelete="CASCADE"
)
# lazy option will allow objects to be nested when transformed for json return
deal: DealTable = Relationship(sa_relationship_kwargs={"lazy": "joined"})
deal: DealTable = Relationship(sa_relationship_kwargs={"lazy": "joined", "single_parent": True})

model_config = {
"from_attributes": True,
Expand Down
68 changes: 15 additions & 53 deletions api/database/models/deal_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,81 +9,43 @@


class DealBase(SQLModel):
buy_price: float = Field(default=0)
buy_total_qty: float = Field(default=0)
buy_timestamp: float = Field(
current_price: float = Field(default=0)
take_profit_price: float = Field(
default=0,
description="Deal timestamps in general should be set by the moment deal action happens, so no default values",
sa_column=Column(BigInteger()),
description="derived from take_profit, while this price gets updated according to market, take_profit percentage doesn't",
)
current_price: float = Field(default=0)
sd: float = Field(default=0)
avg_buy_price: float = Field(default=0)
take_profit_price: float = Field(default=0)
sell_timestamp: float = Field(default=0, sa_column=Column(BigInteger()))
sell_price: float = Field(default=0)
sell_qty: float = Field(default=0)
trailling_stop_loss_price: float = Field(
default=0,
description="take_profit but for trailling, to avoid confusion, trailling_profit_price always be > trailling_stop_loss_price",
)
trailling_profit_price: float = Field(default=0)
stop_loss_price: float = Field(default=0)
trailling_profit: float = Field(
default=0, description="to be deprecated, duplicate field"
)
original_buy_price: float = Field(default=0)

# fields for margin trading
margin_short_loan_principal: float = Field(default=0)
total_interests: float = Field(default=0, gt=-1)
total_commissions: float = Field(default=0, gt=-1)
margin_loan_id: float = Field(default=0)
hourly_interest_rate: float = Field(
default=0,
description="to be deprecated, only used for interest calculation",
sa_column=Column(BigInteger()),
)
margin_short_sell_price: float = Field(
default=0, description="to be deprecated, use opening_price instead"
)
margin_short_loan_interest: float = Field(default=0)
margin_short_buy_back_price: float = Field(
default=0, description="to be deprecated, use opening_price instead"
)
margin_short_sell_qty: float = Field(
default=0, description="to be deprecated, use closing_qty instead"
)
margin_short_buy_back_timestamp: int = Field(
default=0,
description="to be deprecated, use opening_timestamp",
sa_column=Column(BigInteger()),
)
margin_short_base_order: float = Field(
default=0, description="To be merged with base_order"
)
margin_short_sell_timestamp: int = Field(default=0, sa_column=Column(BigInteger()))
margin_short_loan_timestamp: int = Field(default=0, sa_column=Column(BigInteger()))

# Refactored deal prices that combine both margin and spot
opening_price: Optional[float] = Field(
opening_price: float = Field(
default=0,
description="replaces previous buy_price or short_sell_price/margin_short_sell_price",
description="buy price (long spot) or short sell price (short margin trading)",
)
opening_qty: Optional[float] = Field(
opening_qty: float = Field(
default=0,
description="replaces previous buy_total_qty or short_sell_qty/margin_short_sell_qty",
description="buy quantity (long spot) or short sell quantity (short margin trading)",
)
opening_timestamp: Optional[int] = Field(default=0, sa_column=Column(BigInteger()))
closing_price: Optional[float] = Field(
opening_timestamp: int = Field(default=0, sa_column=Column(BigInteger()))
closing_price: float = Field(
default=0,
description="replaces previous sell_price or short_sell_price/margin_short_sell_price",
description="sell price (long spot) or buy back price (short margin trading)",
)
closing_qty: Optional[float] = Field(
closing_qty: float = Field(
default=0,
description="replaces previous sell_qty or short_sell_qty/margin_short_sell_qty",
description="sell quantity (long spot) or buy back quantity (short margin trading)",
)
closing_timestamp: Optional[int] = Field(
closing_timestamp: int = Field(
default=0,
description="replaces previous buy_timestamp or margin/short_sell timestamps",
sa_column=Column(BigInteger()),
)

Expand Down
33 changes: 6 additions & 27 deletions api/database/paper_trading_crud.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from time import time
from typing import Union
from sqlmodel import Session, or_, select, case, desc, asc
from sqlmodel import Session, select, case, desc, asc
from database.models.bot_table import PaperTradingTable
from bots.models import BotModel, BotBase
from database.models.deal_table import DealTable
from database.utils import independent_session
from tools.enum_definitions import BinbotEnums, Status
from collections.abc import Sequence
Expand Down Expand Up @@ -123,42 +121,23 @@ def get(
statement = select(PaperTradingTable)

if status and status in BinbotEnums.statuses:
statement.where(PaperTradingTable.status == status)
statement = statement.where(PaperTradingTable.status == status)

if start_date:
statement.where(PaperTradingTable.created_at >= start_date)
statement = statement.where(PaperTradingTable.created_at >= start_date)

if end_date:
statement.where(PaperTradingTable.created_at <= end_date)

if status and no_cooldown:
current_timestamp = time()
cooldown_condition = cooldown_condition = or_(
PaperTradingTable.status == status,
case(
(
(DealTable.sell_timestamp > 0),
current_timestamp - DealTable.sell_timestamp
< (PaperTradingTable.cooldown * 1000),
),
else_=(
current_timestamp - PaperTradingTable.created_at
< (PaperTradingTable.cooldown * 1000)
),
),
)

statement.where(cooldown_condition)
statement = statement.where(PaperTradingTable.created_at <= end_date)

# sorting
statement.order_by(
statement = statement.order_by(
desc(PaperTradingTable.created_at),
case((PaperTradingTable.status == Status.active, 1), else_=2),
asc(PaperTradingTable.pair),
)

# pagination
statement.limit(limit).offset(offset)
statement = statement.limit(limit).offset(offset)

bots = self.session.exec(statement).all()
self.session.close()
Expand Down
8 changes: 4 additions & 4 deletions api/database/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ def timestamp() -> float:
return int(round(time() * 1000))


def _prepare_comma_seperated_float(value: str | float) -> float | str:
if isinstance(value, str):
return value.replace(",", ".")
def ensure_float(value: str | float | int) -> float:
if isinstance(value, str) or isinstance(value, int):
return float(value)

return value


Amount = Annotated[
float,
BeforeValidator(_prepare_comma_seperated_float),
BeforeValidator(ensure_float),
]
Loading
Loading