Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_sirius-master/strategy/robot_thread.py
5932 views
1
import logging
2
import time
3
import traceback
4
5
from api_calls.get_info import get_candles_by_figi
6
from services.account_info import has_enough_money
7
from services.history_test_data import test_get_candles_by_date, get_test_current_date, get_next_test_current_date
8
from services.instruments_info_cache import make_instrument_key, get_instrument_info_by_key
9
from services.trading_info import get_trading_info_for_key, save_trading_info
10
from strategy.buy_sell_utils import sell, buy
11
from strategy.calculate_utils import calc_profit_percent, add_prices_to_candles
12
from strategy.trade_signal import get_trade_signal
13
from utils.datetime_utils import current_date, string_to_date, date_minus_minutes
14
from utils.settings import settings
15
16
17
# отдельный торговый поток. Возможно, следует иметь по одному отдельному потоку на каждый инструмент торговли.
18
19
def get_candles(instrument_info, last_processed_date):
20
if settings()['MAIN']['mode'] == 'history_test':
21
exchange = instrument_info['exchange']
22
ticker = instrument_info['ticker']
23
return test_get_candles_by_date(exchange, ticker, last_processed_date.timestamp(),
24
get_current_date().timestamp())
25
elif settings()['MAIN']['mode'] == 'sandbox':
26
return get_candles_by_figi(instrument_info['figi'], last_processed_date, get_current_date(),
27
'CANDLE_INTERVAL_1_MIN')['candles']
28
return None
29
30
# TODO take profit/stop loss вынести в trade_signal
31
def process_instrument(account_info, instrument, trading_info, last_processed_date):
32
instrument_key = make_instrument_key(instrument['exchange'], instrument['ticker'])
33
instrument_info = get_instrument_info_by_key(instrument_key)
34
35
instrument_trading_info = get_trading_info_for_key(instrument_key, trading_info)
36
has_share = instrument_trading_info['has_share']
37
38
candles = get_candles(instrument_info, last_processed_date)
39
candles = add_prices_to_candles(candles)
40
41
if len(candles) == 0:
42
return
43
44
last_candle = candles[-1]
45
last_price = last_candle['price']
46
47
# May be take profit or stop loss
48
if has_share:
49
profit_percent = calc_profit_percent(last_price, instrument_trading_info['last_buy_price'])
50
sell_reason = ''
51
if profit_percent > float(settings()['TRADE']['take_profit_percent']):
52
sell_reason = 'take_profit'
53
elif profit_percent < -float(settings()['TRADE']['stop_loss_percent']):
54
sell_reason = 'stop_loss'
55
56
if sell_reason:
57
do_sell(account_info, instrument_info, instrument_trading_info, candles, sell_reason)
58
return
59
60
signal = get_trade_signal(candles)
61
62
if has_share:
63
if signal == 'sell':
64
do_sell(account_info, instrument_info, instrument_trading_info, candles, 'signal')
65
else:
66
if signal == 'buy':
67
do_buy(account_info, instrument_info, instrument_trading_info, candles)
68
69
70
def do_buy(account_info, instrument_info, instrument_trading_info, candles):
71
deal_result = buy(account_info, instrument_info, candles)
72
if deal_result is None:
73
return
74
75
instrument_trading_info['has_share'] = True
76
instrument_trading_info['last_buy_price'] = deal_result['price']
77
78
instrument_trading_info['buy_count'] = instrument_trading_info['buy_count'] + 1
79
instrument_trading_info['balance'] = instrument_trading_info['balance'] - \
80
deal_result['deal_price'] - deal_result['commission']
81
82
logging.info("{} buy, price = {} {} {}"
83
.format(instrument_info['ticker'], deal_result['deal_price'],
84
instrument_info['currency'], deal_result['datetime']))
85
86
87
def do_sell(account_info, instrument_info, instrument_trading_info, candles, reason):
88
deal_result = sell(account_info, instrument_info, candles)
89
if deal_result is None:
90
return
91
92
profit_percent = calc_profit_percent(deal_result['price'], instrument_trading_info['last_buy_price'])
93
94
instrument_trading_info['has_share'] = False
95
instrument_trading_info['last_buy_price'] = 0
96
97
instrument_trading_info['sell_count'] = instrument_trading_info['sell_count'] + 1
98
instrument_trading_info['balance'] = instrument_trading_info['balance'] + \
99
deal_result['deal_price'] - deal_result['commission']
100
101
logging.info("{} sell {}, price = {} {} profit_percent = {} {}"
102
.format(instrument_info['ticker'], reason, deal_result['deal_price'],
103
instrument_info['currency'], round(profit_percent, 2), deal_result['datetime']))
104
105
106
def get_current_date():
107
if settings()['MAIN']['mode'] == 'history_test':
108
return get_test_current_date()
109
else:
110
return current_date()
111
112
113
def is_time_to_process(last_processed_date, current_date, poll_interval_minutes):
114
return (current_date - last_processed_date).total_seconds() >= poll_interval_minutes * 60
115
116
117
def start_robot_thread(account_info, trading_info, instruments, should_stop_callback):
118
logging.info("Robot thread started")
119
120
poll_interval_minutes = int(settings()['TRADE']['poll_interval_minutes'])
121
122
if settings()['MAIN']['mode'] == 'history_test':
123
last_processed_date = get_current_date()
124
else:
125
cur_date = get_current_date()
126
if trading_info['last_processed_date'] is not None:
127
last_processed_date = string_to_date(trading_info['last_processed_date'])
128
if is_time_to_process(last_processed_date, cur_date, poll_interval_minutes):
129
last_processed_date = date_minus_minutes(cur_date, poll_interval_minutes)
130
else:
131
last_processed_date = date_minus_minutes(current_date(), poll_interval_minutes)
132
133
while not should_stop_callback():
134
135
try:
136
cur_date = get_current_date()
137
138
if is_time_to_process(last_processed_date, cur_date, poll_interval_minutes):
139
if settings()['MAIN']['mode'] != 'history_test':
140
logging.info("Processing instruments")
141
if has_enough_money(account_info):
142
for instrument in instruments:
143
process_instrument(account_info, instrument, trading_info, last_processed_date)
144
else:
145
logging.warning("Processing skipped. Robot will not trade until it will have enough money")
146
last_processed_date = cur_date
147
trading_info['last_processed_date'] = str(last_processed_date)
148
149
if settings()['MAIN']['mode'] != 'history_test':
150
save_trading_info(trading_info)
151
152
if settings()['MAIN']['mode'] == 'history_test':
153
get_next_test_current_date()
154
else:
155
time.sleep(1)
156
except Exception as ex:
157
logging.error("Unexpected exception {}".format(ex))
158
traceback.print_exc()
159
time.sleep(10)
160
161
logging.info("Robot thread finished, enter any command to exit")
162
163