153 lines
5.2 KiB
Python
153 lines
5.2 KiB
Python
"""
|
|
This code is an example of applying Trading Strategy for several Tickers.
|
|
The strategy in this code is for demonstration only purposes
|
|
- it outputs OHLCV values.
|
|
Author: Oleg Shpagin, my github: https://github.com/WISEPLAT
|
|
"""
|
|
|
|
import asyncio
|
|
import logging
|
|
import os
|
|
from datetime import timedelta
|
|
from typing import List, Optional
|
|
|
|
from t_tech.invest import AioRequestError, AsyncClient, CandleInterval, HistoricCandle
|
|
from t_tech.invest.async_services import AsyncServices
|
|
from t_tech.invest.utils import now
|
|
|
|
TOKEN = os.environ["INVEST_TOKEN"]
|
|
|
|
logging.basicConfig(format="%(asctime)s %(levelname)s:%(message)s", level=logging.DEBUG)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class LogOnlyCandlesStrategy:
|
|
"""This class is responsible for a strategy. You can put here
|
|
your methods for your strategy."""
|
|
|
|
def __init__(
|
|
self,
|
|
figi: str,
|
|
timeframe: CandleInterval,
|
|
days_back: int,
|
|
check_interval: int,
|
|
client: Optional[AsyncServices],
|
|
):
|
|
self.account_id = None
|
|
self.figi = figi
|
|
self.timeframe = timeframe
|
|
self.days_back = days_back
|
|
self.check_interval = check_interval
|
|
self.client = client
|
|
self.candles: List[HistoricCandle] = []
|
|
|
|
async def get_historical_data(self):
|
|
"""
|
|
Gets historical data for the instrument. Returns list of candles.
|
|
Requests all the candles of timeframe from days_back to now.
|
|
|
|
:return: list of HistoricCandle
|
|
"""
|
|
logger.debug(
|
|
"Start getting historical data for %s days back from now. figi=%s",
|
|
self.days_back,
|
|
self.figi,
|
|
)
|
|
async for candle in self.client.get_all_candles(
|
|
figi=self.figi,
|
|
from_=now() - timedelta(days=self.days_back),
|
|
to=now(),
|
|
interval=self.timeframe,
|
|
):
|
|
if candle not in self.candles:
|
|
if candle.is_complete:
|
|
self.candles.append(candle)
|
|
logger.debug("Found %s - figi=%s", candle, self.figi)
|
|
|
|
async def ensure_market_open(self):
|
|
"""
|
|
Ensure that the market is open. Loop until the instrument is available.
|
|
:return: when instrument is available for trading
|
|
"""
|
|
trading_status = await self.client.market_data.get_trading_status(
|
|
figi=self.figi
|
|
)
|
|
while not (
|
|
trading_status.market_order_available_flag
|
|
and trading_status.api_trade_available_flag
|
|
):
|
|
logger.debug("Waiting for the market to open. figi=%s", self.figi)
|
|
await asyncio.sleep(60)
|
|
trading_status = await self.client.market_data.get_trading_status(
|
|
figi=self.figi
|
|
)
|
|
|
|
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)
|
|
|
|
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 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)
|
|
|
|
|
|
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)
|