refactor symbol and executor

This commit is contained in:
Ichinga Samuel
2023-10-24 13:59:28 +01:00
parent 21043dd326
commit aa39fdf033
14 changed files with 214 additions and 13 deletions
+4 -8
View File
@@ -19,7 +19,7 @@ class Bot:
Attributes:
account (Account): Account Object.
executor: The default thread executor.
symbols (set[Symbols]): A set of symbols for the trading session
symbols (list[Symbols]): A set of symbols for the trading session
"""
account: Account = Account()
@@ -82,7 +82,6 @@ class Bot:
Notes:
Make sure the symbol has been added to the market
"""
self.symbols.add(strategy.symbol)
self.executor.add_worker(strategy)
def add_strategies(self, strategies: Iterable[Strategy]):
@@ -104,9 +103,8 @@ class Bot:
[self.add_strategy(strategy(symbol=symbol, params=params)) for symbol in self.symbols]
async def init_symbols(self):
"""Initialize the symbols for the current trading session. This method is called internally by the bot.
"""
syms = [self.init_symbol(symbol) for symbol in self.symbols]
"""Initialize the symbols for the current trading session. This method is called internally by the bot."""
syms = [self.init_symbol(strategy.symbol) for strategy in self.executor.workers]
await asyncio.gather(*syms, return_exceptions=True)
async def init_symbol(self, symbol: Symbol) -> Symbol:
@@ -123,9 +121,7 @@ class Bot:
if self.account.has_symbol(symbol):
init = await symbol.init()
if init:
self.symbols.add(symbol)
return symbol
self.symbols.discard(symbol)
logger.warning(f'Unable to initialize symbol {symbol}')
self.symbols.remove(symbol)
logger.warning(f'{symbol} not a available for this market')
-1
View File
@@ -13,7 +13,6 @@ class Executor:
workers (list): List of strategies.
coroutines (dict[Coroutine, dict]): A dictionary of coroutines to run in the executor
functions (dict[Callable, dict]): A dictionary of functions to run in the executor
"""
def __init__(self, bot=None):
+2 -1
View File
@@ -47,7 +47,8 @@ class Strategy(ABC):
self.parameters = params.copy() if isinstance(params, dict) else {}
self.parameters['symbol'] = symbol.name
self.parameters['name'] = self.name or self.__class__.__name__
self.sessions = sessions or Sessions(Session(start=0, end=23))
self.sessions = sessions or Sessions(Session(start=0, end=dtime(hour=23, minute=59, second=59,
microsecond=999999)))
def __repr__(self):
return f"{self.name}({self.symbol!r})"
+15 -1
View File
@@ -1,6 +1,7 @@
"""Symbol class for handling a financial instrument."""
from datetime import datetime
from logging import getLogger
from math import log10, ceil
from .core.constants import TimeFrame, CopyTicks
from .core.models import SymbolInfo, BookInfo
@@ -135,7 +136,20 @@ class Symbol(SymbolInfo):
"""
return await self.mt5.market_book_release(self.name)
async def compute_volume(self, *, amount: float, pips: float, use_limits: bool = True) -> float:
def check_volume(self, volume) -> tuple[bool, float]:
check = self.volume_min <= volume <= self.volume_max
if check:
return check, volume
if not check and volume < self.volume_min:
return check, self.volume_min
else:
return check, self.volume_max
def round_off_volume(self, volume):
step = ceil(abs(log10(self.volume_step)))
return round(volume, step)
async def compute_volume(self, *, amount: float, pips: float, use_limits: bool = False) -> float:
"""Computes the volume of a trade based on the amount and the number of pips to target.
This is a dummy method that returns the minimum volume of the symbol. It is meant to be overridden by a subclass
that implements the computation of volume.
+2 -1
View File
@@ -54,7 +54,8 @@ class Trader:
"""
# check if pips is passed in as a keyword argument, if not use the pips attribute of the ram instance
pips = kwargs.get('pips', 0) or self.ram.pips
self.order.volume = kwargs.get('volume', self.ram.volume) or await self.ram.get_volume(symbol=self.symbol, pips=pips)
self.order.volume = kwargs.get('volume', self.ram.volume) or await self.ram.get_volume(symbol=self.symbol,
pips=pips)
self.order.type = order_type
await self.set_order_limits(pips=pips)