Skip to content

Commit

Permalink
Setup new bot data controller (#636)
Browse files Browse the repository at this point in the history
* Setup new bot data controller

* Simplify database operations

By creating simpler and atomic db operations as a separate layer, we reduce complexity for testing (duplicated code), decouple dependencies of database and services and also reduce circular imports.

* Refactor and unify simulated orders (paper trading)

* Fix tests for new SQL bots migration

* Refactor all data models to use a single BotModel

The reason behind this is that pydantic table models are SQL models which are different from traditional pydantic models. So to reduce repetition, we have to create a BotBase which is inherited by the "guardian" i.e. the BotModel which is use to guard data everywhere, and the separation of database tables i.e. BotTable

* Fix all SQLModel vs Pydantic model compatibility issues
* Refactor deals into a singleton

The DealFactory is a literal factory, not a factory pattern, in that we do know what kind of object we are creating, but we are unifying into a single point of entry (singleton)
  • Loading branch information
carkod authored Dec 26, 2024
1 parent 8e22885 commit b25190f
Show file tree
Hide file tree
Showing 49 changed files with 2,781 additions and 2,248 deletions.
1 change: 1 addition & 0 deletions api/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.11
3 changes: 2 additions & 1 deletion api/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ verify_ssl = false

[packages]
uvicorn = "*"
fastapi = "==0.110.0"
fastapi = "==0.115.6"
pymongo = "==4.6.3"
python-jose = "*"
passlib = "*"
Expand All @@ -30,6 +30,7 @@ psycopg2 = "*"
pydantic = {extras = ["email"], version = "*"}
alembic-postgresql-enum = "*"
python-dotenv = "*"
psycopg = "*"

[dev-packages]
pytest = "==8.1.1"
Expand Down
580 changes: 249 additions & 331 deletions api/Pipfile.lock

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions api/account/account.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import requests
import os
import pandas
from apis import BinbotApi
from tools.handle_error import (
handle_binance_errors,
Expand All @@ -9,8 +11,6 @@
from database.db import setup_db
from requests_cache import CachedSession, MongoCache
from pymongo import MongoClient
import os
import pandas
from decimal import Decimal


Expand Down Expand Up @@ -253,8 +253,7 @@ def matching_engine(self, symbol: str, order_side: bool, qty=None):
@param: qty - quantity wanted to be bought/sold
"""

params = [("symbol", symbol)]
res = requests.get(url=self.order_book_url, params=params)
res = requests.get(url=self.order_book_url, params={"symbol": symbol})
data = handle_binance_errors(res)

if order_side:
Expand Down
14 changes: 8 additions & 6 deletions api/account/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
from bson.objectid import ObjectId
from fastapi.responses import JSONResponse
from account.controller import AssetsController
from autotrade.controller import AutotradeSettingsController
from bots.schemas import BotSchema
from deals.controllers import CreateDealController
from database.models.bot_table import BotTable
from database.autotrade_crud import AutotradeCrud
from bots.models import BotModel
from deals.factory import DealFactory
from tools.handle_error import json_response, json_response_error, json_response_message
from tools.round_numbers import round_numbers
from tools.exceptions import BinanceErrors, LowBalanceCleanupError
Expand All @@ -15,7 +16,7 @@ class Assets(AssetsController):
def __init__(self):
self.usd_balance = 0
self.exception_list = []
self.fiat = AutotradeSettingsController().get_settings().balance_to_use
self.fiat = AutotradeCrud().get_settings().balance_to_use

def get_pnl(self, days=7):
current_time = datetime.now()
Expand Down Expand Up @@ -346,8 +347,9 @@ def one_click_liquidation(self, pair: str) -> JSONResponse:
bot = self._db.bots.find_one({"status": Status.active, "pair": pair})
if not bot:
return bot
active_bot = BotSchema.model_validate(bot)
deal = CreateDealController(active_bot, db_collection="bots")
active_bot = BotModel.model_validate(bot)
deal = DealFactory(active_bot, db_table=BotTable)

if active_bot.strategy == Strategy.margin_short:
deal.margin_liquidation(pair)

Expand Down
2 changes: 1 addition & 1 deletion api/alembic/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
from database.api_db import db_url
from database.utils import db_url
from database.models import SQLModel


Expand Down
10 changes: 5 additions & 5 deletions api/autotrade/routes.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import Annotated

from sqlmodel import Session
from database.autotrade_crud import AutotradeCrud
from tools.enum_definitions import AutotradeSettingsDocument
from database.utils import get_session
from autotrade.controller import AutotradeSettingsController
from autotrade.schemas import AutotradeSettingsResponse, AutotradeSettingsSchema
from fastapi import APIRouter, Depends, HTTPException
from pydantic import ValidationError
Expand All @@ -22,7 +22,7 @@ def edit_settings(
these use real money and real Binance transactions
"""
try:
result = AutotradeSettingsController(session=session).edit_settings(item)
result = AutotradeCrud(session=session).edit_settings(item)
if not result:
raise HTTPException(status_code=404, detail="Autotrade settings not found")
return json_response({"message": "Successfully updated settings"})
Expand All @@ -37,7 +37,7 @@ def edit_settings(
@autotrade_settings_blueprint.get("/bots", tags=["autotrade settings"])
def get_settings(session: Session = Depends(get_session)):
try:
deserialized_data = AutotradeSettingsController(session=session).get_settings()
deserialized_data = AutotradeCrud(session=session).get_settings()
return json_response(
{
"message": "Successfully retrieved settings",
Expand All @@ -57,7 +57,7 @@ def get_test_autotrade_settings(
session: Session = Depends(get_session),
):
try:
deserialized_data = AutotradeSettingsController(
deserialized_data = AutotradeCrud(
document_id=AutotradeSettingsDocument.test_autotrade_settings,
session=session,
).get_settings()
Expand All @@ -77,7 +77,7 @@ def edit_test_autotrade_settings(
session: Session = Depends(get_session),
):
try:
data = AutotradeSettingsController(
data = AutotradeCrud(
document_id=AutotradeSettingsDocument.test_autotrade_settings,
session=session,
).edit_settings(item)
Expand Down
Loading

0 comments on commit b25190f

Please sign in to comment.