Skip to content

Commit

Permalink
Add position to signal
Browse files Browse the repository at this point in the history
  • Loading branch information
vitassuper committed Jun 28, 2023
1 parent 4fe12ed commit 507b082
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 35 deletions.
28 changes: 28 additions & 0 deletions migrations/versions/2023-06-28_update_deals_table_add_position.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""update_deals_table_add_position
Revision ID: 3d9358bcf686
Revises: 900e1be8f4c6
Create Date: 2023-06-28 21:50:47.237178
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '3d9358bcf686'
down_revision = '900e1be8f4c6'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('deals', sa.Column('position', sa.SmallInteger(), nullable=True))
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
1 change: 1 addition & 0 deletions src/app/models/deal.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ class Deal(Base):
date_close: Mapped[datetime] = mapped_column(DateTime(), nullable=True, default=None)
pnl: Mapped[decimal] = mapped_column(Numeric(), nullable=True)
bot_id: Mapped[int] = mapped_column(Integer(), nullable=False)
position: Mapped[int] = mapped_column(Integer(), nullable=True)
order: Mapped[List["Order"]] = relationship(cascade="all, delete", passive_deletes=True)
16 changes: 10 additions & 6 deletions src/app/repositories/deal.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import decimal
from datetime import datetime
from typing import Optional
from typing import Optional, Union

from sqlalchemy import select, and_, func

from src.app.models.deal import Deal
from src.db.session import get_async_session


async def create_deal(bot_id: int, pair: str, date_open: datetime, pnl: Optional[decimal] = None):
async def create_deal(bot_id: int, pair: str, date_open: datetime, position: Union[int, None] = None):
async with get_async_session() as session:
deal = Deal(
bot_id=bot_id,
pair=pair,
date_open=date_open,
pnl=pnl
position=position
)
session.add(deal)
await session.commit()
Expand All @@ -35,13 +35,17 @@ async def update_deal(deal_id: int, **update_values) -> Deal:
return deal


async def get_bot_last_deal(bot_id: int, pair: str) -> Deal:
async def get_bot_last_deal(bot_id: int, pair: str, position: Union[int, None] = None) -> Deal:
async with get_async_session() as session:
query = select(Deal).where(and_(Deal.bot_id == bot_id, Deal.pair == pair, Deal.date_close.is_(None))).order_by(
Deal.id.desc())
deals = await session.execute(query)

return deals.scalar()
if position is not None:
query = query.where(Deal.position == position)

result = await session.execute(query)

return result.scalar()


async def get_deal_by_id(deal_id: int) -> Deal:
Expand Down
4 changes: 4 additions & 0 deletions src/app/schemas/signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ class OpenSignal(BaseModel):
type_of_signal: Literal['open']
pair: str
amount: float
position: Optional[int]


class CloseSignal(BaseModel):
bot_id: int
type_of_signal: Literal['close']
pair: str
position: Optional[int]
amount: Optional[float]
deal_id: Optional[int]

Expand All @@ -22,3 +24,5 @@ class AddSignal(BaseModel):
type_of_signal: Literal['add']
pair: str
amount: float
deal_id: Optional[int]
position: Optional[int]
10 changes: 5 additions & 5 deletions src/app/services/deal.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
from datetime import datetime
from typing import List
from typing import List, Union

from src.app.models import Deal
from src.app.repositories import deal as repository
from src.bot.exceptions.not_found_exception import NotFoundException


async def create_deal(bot_id: int, pair: str, date_open: datetime) -> Deal:
return await repository.create_deal(bot_id=bot_id, pair=pair, date_open=date_open)
async def create_deal(bot_id: int, pair: str, date_open: datetime, position: Union[int, None] = None) -> Deal:
return await repository.create_deal(bot_id=bot_id, pair=pair, date_open=date_open, position=position)


async def increment_safety_orders_count(deal_id: int) -> int:
return await repository.increment_safety_orders_count(deal_id=deal_id)


async def get_deal(bot_id: int, pair: str) -> Deal:
deal = await repository.get_bot_last_deal(bot_id=bot_id, pair=pair)
async def get_deal(bot_id: int, pair: str, position: Union[int, None] = None) -> Deal:
deal = await repository.get_bot_last_deal(bot_id=bot_id, pair=pair, position=position)

if not deal:
raise NotFoundException(
Expand Down
7 changes: 5 additions & 2 deletions src/bot/exchange/bot.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Union

from src.app.repositories.bot import get_bot
from src.app.services.bot import get_copy_bots
from src.app.services.deal import is_deal_exist
Expand All @@ -15,12 +17,13 @@


class Bot:
def __init__(self, bot_id: int, pair: str, type_of_signal: str) -> None:
def __init__(self, bot_id: int, pair: str, type_of_signal: str, position: Union[int, None] = None) -> None:
self.margin_type = None
self.exchange = None
self.type_of_signal = type_of_signal
self.bot_id = bot_id
self.pair = pair
self.position = position

async def get_copy_bots(self):
if self.bot_id in range(100, 300):
Expand Down Expand Up @@ -96,7 +99,7 @@ def get_strategy(self, side: BaseSide):
if self.bot_id == 3 or self.bot_id == 1 or self.bot_id == 2:
return SimpleStrategy(bot_id=self.bot_id, side=side, pair=self.pair)

return GridStrategy(bot_id=self.bot_id, side=side, pair=self.pair)
return GridStrategy(bot_id=self.bot_id, side=side, pair=self.pair, position=self.position)

def get_bot_name(self):
return f'Bot id: {self.bot_id} ({self.exchange.get_exchange_name()})'
Expand Down
18 changes: 10 additions & 8 deletions src/bot/exchange/strategies/base_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,32 @@


class BaseStrategy(metaclass=abc.ABCMeta):
def __init__(self, bot_id: int, side: BaseSide, pair: str) -> None:
def __init__(self, bot_id: int, side: BaseSide, pair: str, position: Union[int, None] = None) -> None:
self.bot_id = bot_id
self.side = side
self.exchange = side.exchange
self.pair = pair
self.position = position

self.contract_size = Decimal(self.exchange.get_market(pair=pair)['contractSize'])

self.strategy_helper = StrategyHelper(taker_fee=Decimal(self.exchange.ccxt_exchange.market(self.pair)['taker']),
side=side.get_side_type(), contract_size=self.contract_size)

self.db_helper = StrategyDBHelper(side=side.get_side_type(), bot_id=self.bot_id, pair=self.pair)
self.db_helper = StrategyDBHelper(side=side.get_side_type(), bot_id=self.bot_id, pair=self.pair,
position=self.position)

# Abstract methods
@abc.abstractmethod
async def open_deal_process(self, base_amount: Decimal):
pass

@abc.abstractmethod
async def close_deal_process(self, amount: float = None, deal: Union[Deal, None] = None) -> ClosedDeal:
async def close_deal_process(self, deal: Deal, amount: float = None) -> ClosedDeal:
pass

@abc.abstractmethod
async def average_deal_process(self, base_amount: Decimal):
async def average_deal_process(self, deal: Deal, base_amount: Decimal):
pass

# Helpers
Expand All @@ -60,9 +62,9 @@ async def open_deal(self, amount: float) -> OpenedDealMessage:
side=self.side.get_side_type()
)

async def average_deal(self, amount: float) -> AveragedDealMessage:
async def average_deal(self, amount: float, deal: Deal) -> AveragedDealMessage:
base_amount = self.get_base_amount(quote_amount=Decimal(amount))
safety_count, quote_amount = await self.average_deal_process(base_amount=base_amount)
safety_count, quote_amount = await self.average_deal_process(deal=deal, base_amount=base_amount)

deal = await self.db_helper.get_deal()
deal_stats = await self.db_helper.get_deal_stats(deal_id=deal.id)
Expand All @@ -81,8 +83,8 @@ async def average_deal(self, amount: float) -> AveragedDealMessage:
self.contract_size)
)

async def close_deal(self, amount: float, deal: Union[Deal, None] = None) -> ClosedDealMessage:
closed_deal = await self.close_deal_process(amount=amount, deal=deal)
async def close_deal(self, amount: float, deal: Deal) -> ClosedDealMessage:
closed_deal = await self.close_deal_process(deal=deal, amount=amount)

return ClosedDealMessage(
title=f'Bot id: {self.bot_id} ({self.exchange.get_exchange_name()})',
Expand Down
9 changes: 2 additions & 7 deletions src/bot/exchange/strategies/grid_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,22 @@ async def open_deal_process(self, base_amount: Decimal):

return order.quote_amount, price

async def average_deal_process(self, base_amount: Decimal):
async def average_deal_process(self, deal: Deal, base_amount: Decimal):
# Not necessary for current strategy
# self.ensure_deal_opened()

self.set_leverage(20)
order = self.average_market_order(amount=base_amount)

deal = await self.db_helper.get_or_create_deal()

await self.db_helper.create_average_order(deal_id=deal.id, price=order.price, volume=order.volume)

safety_count = await self.db_helper.average_deal(deal_id=deal.id)

return safety_count, order.quote_amount

async def close_deal_process(self, amount: float = None, deal: Union[Deal, None] = None) -> ClosedDeal:
async def close_deal_process(self, deal: Deal, amount: float = None) -> ClosedDeal:
self.ensure_deal_opened()

if not deal:
deal = await self.db_helper.get_deal()

deal_stats = await self.db_helper.get_deal_stats(deal_id=deal.id)

order = self.close_market_order(deal_stats.total_volume)
Expand Down
7 changes: 4 additions & 3 deletions src/bot/exchange/strategy_db_helper.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import datetime
from decimal import Decimal
from typing import Literal
from typing import Literal, Union

from src.app.models import Order, Deal
from src.app.services.deal import update_deal, get_deal, create_deal, increment_safety_orders_count, get_or_create_deal
Expand All @@ -11,10 +11,11 @@


class StrategyDBHelper:
def __init__(self, side: SideType, bot_id: int, pair: str):
def __init__(self, side: SideType, bot_id: int, pair: str, position: Union[int, None] = None):
self.side = side
self.bot_id = bot_id
self.pair = pair
self.position = position

def get_order_side(self, action: Literal['open', 'close']) -> OrderSideType:
mapping = {
Expand Down Expand Up @@ -45,7 +46,7 @@ async def get_or_create_deal(self) -> Deal:
return await get_or_create_deal(bot_id=self.bot_id, pair=self.pair)

async def open_deal(self) -> Deal:
return await create_deal(bot_id=self.bot_id, pair=self.pair, date_open=datetime.now())
return await create_deal(bot_id=self.bot_id, pair=self.pair, date_open=datetime.now(), position=self.position)

async def get_deal_stats(self, deal_id: int) -> DealStats:
return await get_deal_stats(deal_id=deal_id)
Expand Down
19 changes: 15 additions & 4 deletions src/bot/signal_dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from src.bot.exchange.notifiers.telegram_notifier import TelegramNotifier
from .exceptions.not_found_exception import NotFoundException
from .singal_dispatcher_spawner import spawn_and_dispatch
from src.app.services.deal import get_deal_by_id
from src.app.services.deal import get_deal_by_id, get_deal


class SignalDispatcher:
Expand All @@ -25,10 +25,12 @@ def __init__(
async def dispatch(self):
try:
self.notifier.add_message_to_stack(
f'Position: {self.signal.position}\n'
f'Received <b>{self.signal.type_of_signal}</b> signal: pair: {self.signal.pair}' + (
f' amount: {self.signal.amount}' if hasattr(self.signal, 'amount') else ''))

bot = Bot(bot_id=self.signal.bot_id, pair=self.signal.pair, type_of_signal=self.signal.type_of_signal)
bot = Bot(bot_id=self.signal.bot_id, pair=self.signal.pair, type_of_signal=self.signal.type_of_signal,
position=self.signal.position)

for copy_bot in await bot.get_copy_bots():
copy_signal = deepcopy(self.signal)
Expand Down Expand Up @@ -70,12 +72,21 @@ async def handle_open_signal(self):
self.notifier.add_message_to_stack(str(opened_position_message))

async def handle_average_signal(self):
averaged_position_message = await self.strategy.average_deal(amount=self.signal.amount)
### get_or_create_deal

deal = await self.get_deal_from_signal()
averaged_position_message = await self.strategy.average_deal(amount=self.signal.amount, deal=deal)

self.notifier.add_message_to_stack(str(averaged_position_message))

async def handle_close_signal(self):
deal = await get_deal_by_id(deal_id=self.signal.deal_id)
deal = await self.get_deal_from_signal()
closed_position_message = await self.strategy.close_deal(amount=self.signal.amount, deal=deal)

self.notifier.add_message_to_stack(str(closed_position_message))

async def get_deal_from_signal(self):
if self.signal.deal_id:
return await get_deal_by_id(deal_id=self.signal.deal_id)
else:
return await get_deal(bot_id=self.signal.bot_id, pair=self.strategy.pair, position=self.signal.position)

0 comments on commit 507b082

Please sign in to comment.