-
Notifications
You must be signed in to change notification settings - Fork 34
/
main_live_one_ticker.py
98 lines (84 loc) · 7.38 KB
/
main_live_one_ticker.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
from datetime import datetime, time
import backtrader as bt
from BackTraderQuik.QKStore import QKStore # Хранилище QUIK
class LimitCancel(bt.Strategy):
"""
Выставляем заявку на покупку на n% ниже цены закрытия
Если за 1 бар заявка не срабатывает, то закрываем ее
Если срабатывает, то закрываем позицию. Неважно, с прибылью или убытком
"""
params = ( # Параметры торговой системы
('LimitPct', 1), # Заявка на покупку на n% ниже цены закрытия
)
def log(self, txt, dt=None):
"""Вывод строки с датой на консоль"""
dt = bt.num2date(self.datas[0].datetime[0]) if dt is None else dt # Заданная дата или дата текущего бара
print(f'{dt.strftime("%d.%m.%Y %H:%M")}, {txt}') # Выводим дату и время с заданным текстом на консоль
def __init__(self):
"""Инициализация торговой системы"""
self.isLive = False # Сначала будут приходить исторические данные, затем перейдем в режим реальной торговли
self.order = None # Заявка на вход/выход из позиции
def next(self):
"""Получение следующего исторического/нового бара"""
if not self.isLive: # Если не в режиме реальной торговли
return # то выходим, дальше не продолжаем
if self.order and self.order.status == bt.Order.Submitted: # Если заявка не исполнена (отправлена брокеру)
return # то ждем исполнения, выходим, дальше не продолжаем
if not self.position: # Если позиции нет
if self.order and self.order.status == bt.Order.Accepted: # Если заявка не исполнена (принята брокером)
self.cancel(self.order) # то снимаем ее
limitPrice = self.data.close[0] * (1 - self.p.LimitPct / 100) # На n% ниже цены закрытия
limitPrice = 0.015050
self.order = self.buy(exectype=bt.Order.Limit, price=limitPrice) # Лимитная заявка на покупку
else: # Если позиция есть
self.order = self.close() # Заявка на закрытие позиции по рыночной цене
def notify_data(self, data, status, *args, **kwargs):
"""Изменение статуса приходящих баров"""
dataStatus = data._getstatusname(status) # Получаем статус (только при LiveBars=True)
print(dataStatus) # Не можем вывести в лог, т.к. первый статус DELAYED получаем до первого бара (и его даты)
self.isLive = dataStatus == 'LIVE' # Режим реальной торговли
def notify_order(self, order):
"""Изменение статуса заявки"""
if order.status in (bt.Order.Created, bt.Order.Submitted, bt.Order.Accepted): # Если заявка создана, отправлена брокеру, принята брокером (не исполнена)
self.log(f'Alive Status: {order.getstatusname()}. TransId={order.ref}')
elif order.status in (bt.Order.Canceled, bt.Order.Margin, bt.Order.Rejected, bt.Order.Expired): # Если заявка отменена, нет средств, заявка отклонена брокером, снята по времени (снята)
self.log(f'Cancel Status: {order.getstatusname()}. TransId={order.ref}')
elif order.status == bt.Order.Partial: # Если заявка частично исполнена
self.log(f'Part Status: {order.getstatusname()}. TransId={order.ref}')
elif order.status == bt.Order.Completed: # Если заявка полностью исполнена
if order.isbuy(): # Заявка на покупку
self.log(f'Bought @{order.executed.price:.2f}, Cost={order.executed.value:.2f}, Comm={order.executed.comm:.2f}')
elif order.issell(): # Заявка на продажу
self.log(f'Sold @{order.executed.price:.2f}, Cost={order.executed.value:.2f}, Comm={order.executed.comm:.2f}')
self.order = None # Сбрасываем заявку на вход в позицию
def notify_trade(self, trade):
"""Изменение статуса позиции"""
if trade.isclosed: # Если позиция закрыта
self.log(f'Trade Profit, Gross={trade.pnl:.2f}, NET={trade.pnlcomm:.2f}')
if __name__ == '__main__': # Точка входа при запуске этого скрипта
cerebro = bt.Cerebro() # Инициируем "движок" BackTrader
# open:
# clientCode = 'XXX' # Код клиента (присваивается брокером)
# firmId = 'MC0139600000' # Код фирмы (присваивается брокером) # Счет L01-00000F00
# tradeAccountId = 'L01-00000F00'
# finam:
clientCode = '593458R8NYF' # Код клиента (присваивается брокером)
clientCodeForOrders = 'FZQU251223A' # Код клиента (присваивается брокером) # номер терминала @
firmId = 'MC0061900000' # Код фирмы (присваивается брокером) # Счет L01+00000F00
tradeAccountId = 'L01+00000F00'
symbol = 'TQBR.VTBR'
# symbol = 'SPBFUT.SiH2'
cerebro.addstrategy(LimitCancel, LimitPct=1) # Добавляем торговую систему с лимитным входом в n%
store = QKStore() # Хранилище QUIK (QUIK на локальном компьютере)
# store = QKStore(Host='<Ваш IP адрес>') # Хранилище QUIK (К QUIK на удаленном компьютере обращаемся по IP или названию)
# broker = store.getbroker(use_positions=False) # Брокер со счетом по умолчанию (срочный рынок РФ)
broker = store.getbroker(use_positions=False, ClientCode=clientCode, ClientCodeForOrders=clientCodeForOrders,
FirmId=firmId, TradeAccountId=tradeAccountId, LimitKind=2, CurrencyCode='SUR',
IsFutures=False) # Брокер со счетом фондового рынка РФ
cerebro.setbroker(broker) # Устанавливаем брокера
data = store.getdata(dataname=symbol, timeframe=bt.TimeFrame.Minutes, compression=1,
fromdate=datetime(2022, 4, 14), sessionstart=time(7, 0),
LiveBars=True) # Исторические и новые минутные бары за все время
cerebro.adddata(data) # Добавляем данные
cerebro.addsizer(bt.sizers.FixedSize, stake=10000) # Кол-во акций для покупки/продажи
cerebro.run() # Запуск торговой системы