Хочу поделиться полезной наработкой для тех, кто разрабатывает торговых роботов - шаблоном кода для асинхронной торговой стратегии (live и offline), этот код можно достаточно просто перестраивать под любое API провайдера данных по инструментам.
Сам код опубликовал на Github Тинькофф: https://github.com/Tinkoff/invest-python/blob/main/examples/wiseplat_live_strategy_print_ohlcv.py
Сразу приведу ссылку на этот же мною переработанный код, который использует данные из открытого доступа предоставляемые провайдером - биржей MOEX (даже не нужно получать токен) по торговым инструментам (правда с задержкой в 15 минут) https://github.com/WISEPLAT/Hackathon-Finam-NN-Trade-Robot/blob/master/7_live_strategy.py
Структура кода торговой стратегии
Обычно код для торговой стратегии состоит из следующих блоков:
Блок запуска кода
Блок подключения по API к провайдеру данных, в цикле которого по каждому инструменту запускается отдельный экземпляр торговой стратегии
-
Каждый запущенный экземпляр стратегии имеет:
Блок входа (однократное выполнение кода), обычно используется для инициализации переменных и т.д.
-
Блок бесконечного цикла, в котором уже и выполняется логика торговой стратегии
например проверка, что рынок открыт - или ожидание его открытия
получение исторических и живых данных по инструменту
обработка полученных данных торговой логикой
Теперь давайте посмотри поближе на этот код.
Блок запуска кода
if __name__ == "__main__":
sber_figi = "BBG004730N88"
vtbr_figi = "BBG004730ZJ9"
portfolio = {sber_figi, vtbr_figi}
timeframe = CandleInterval.CANDLE_INTERVAL_1_MIN
days_back = 1
check_interval = 10 # seconds to check interval for new completed candle
loop = asyncio.get_event_loop()
task = loop.create_task(
run_strategy(
portfolio=portfolio,
timeframe=timeframe,
days_back=days_back,
check_interval=check_interval,
)
)
loop.run_until_complete(task)
Блок подключения по API к провайдеру данных
async def run_strategy(portfolio, timeframe, days_back, check_interval):
"""From this function we are starting
strategy for every ticker from portfolio.
"""
async with AsyncClient(token=TOKEN, app_name="TinkoffApp") as client:
strategy_tasks = []
for instrument in portfolio:
strategy = LogOnlyCandlesStrategy(
figi=instrument,
timeframe=timeframe,
days_back=days_back,
check_interval=check_interval,
client=client,
)
strategy_tasks.append(asyncio.create_task(strategy.start()))
await asyncio.gather(*strategy_tasks)
Блок входа (однократное выполнение кода)
async def start(self):
"""Strategy starts from this function."""
if self.account_id is None:
try:
self.account_id = (
(await self.client.users.get_accounts()).accounts.pop().id
)
except AioRequestError as are:
logger.error("Error taking account id. Stopping strategy. %s", are)
return
await self.main_cycle()
Блок бесконечного цикла (выполнение логики торговой стратегии)
async def main_cycle(self):
"""Main cycle for live strategy."""
while True:
try:
await self.ensure_market_open()
await self.get_historical_data()
# put your strategy code here for live
# to generate signals for buying or selling tickers
logger.debug(
"- live mode: run some strategy code to buy or sell - figi=%s",
self.figi,
)
except AioRequestError as are:
logger.error("Client error %s", are)
await asyncio.sleep(self.check_interval)
Доступные выше по ссылкам примеры кода для асинхронной торговой стратегии постарался хорошо задокументировать.
Надеюсь, что это окажется вам полезным +1 и поможет вам сэкономить ваше время!