forked from robcarver17/pysystemtrade
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun_system_classic.py
204 lines (162 loc) · 6.59 KB
/
run_system_classic.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
"""
this:
- gets capital from the database (earmarked with a strategy name)
- runs a backtest using that capital level, and mongodb data
- gets the final positions and position buffers
- writes these into a table (earmarked with a strategy name)
"""
import datetime
from syscore.constants import arg_not_supplied
from syscore.exceptions import missingData
from sysdata.config.configdata import Config
from sysdata.data_blob import dataBlob
from sysobjects.production.optimal_positions import (
bufferedOptimalPositions,
)
from sysobjects.production.tradeable_object import instrumentStrategy
from sysproduction.data.currency_data import dataCurrency
from sysproduction.data.capital import dataCapital
from sysproduction.data.contracts import dataContracts
from sysproduction.data.optimal_positions import dataOptimalPositions
from sysproduction.data.sim_data import get_sim_data_object_for_production
from sysproduction.data.backtest import store_backtest_state
from syslogging.logger import *
from systems.provided.futures_chapter15.basesystem import futures_system
from systems.basesystem import System
class runSystemClassic(object):
def __init__(
self,
data: dataBlob,
strategy_name: str,
backtest_config_filename=arg_not_supplied,
):
if backtest_config_filename is arg_not_supplied:
raise Exception("Need to supply config filename")
self.data = data
self.strategy_name = strategy_name
self.backtest_config_filename = backtest_config_filename
## DO NOT CHANGE THE NAME OF THIS FUNCTION
def run_backtest(self):
strategy_name = self.strategy_name
data = self.data
base_currency, notional_trading_capital = self._get_currency_and_capital()
system = self.system_method(
notional_trading_capital=notional_trading_capital,
base_currency=base_currency,
)
function_to_call_on_update = self.function_to_call_on_update
function_to_call_on_update(
data=data, strategy_name=strategy_name, system=system
)
store_backtest_state(data, system, strategy_name=strategy_name)
## MODIFY THIS WHEN INHERITING FOR A DIFFERENT STRATEGY
## ARGUMENTS MUST BE: data: dataBlob, strategy_name: str, system: System
@property
def function_to_call_on_update(self):
return updated_buffered_positions
def _get_currency_and_capital(self):
data = self.data
strategy_name = self.strategy_name
capital_data = dataCapital(data)
try:
notional_trading_capital = capital_data.get_current_capital_for_strategy(
strategy_name
)
except missingData:
# critical log will send email
error_msg = (
"Capital data is missing for %s: can't run backtest" % strategy_name
)
data.log.critical(error_msg)
raise Exception(error_msg)
currency_data = dataCurrency(data)
base_currency = currency_data.get_base_currency()
self.data.log.debug(
"Using capital of %s %.2f" % (base_currency, notional_trading_capital)
)
return base_currency, notional_trading_capital
# DO NOT CHANGE THE NAME OF THIS FUNCTION; IT IS HARDCODED INTO CONFIGURATION FILES
# BECAUSE IT IS ALSO USED TO LOAD BACKTESTS
def system_method(
self,
notional_trading_capital: float = arg_not_supplied,
base_currency: str = arg_not_supplied,
) -> System:
data = self.data
backtest_config_filename = self.backtest_config_filename
system = production_classic_futures_system(
data,
backtest_config_filename,
log=data.log,
notional_trading_capital=notional_trading_capital,
base_currency=base_currency,
)
return system
def production_classic_futures_system(
data: dataBlob,
config_filename: str,
log=get_logger("futures_system"),
notional_trading_capital: float = arg_not_supplied,
base_currency: str = arg_not_supplied,
) -> System:
sim_data = get_sim_data_object_for_production(data)
config = Config(config_filename)
# Overwrite capital and base currency
if notional_trading_capital is not arg_not_supplied:
config.notional_trading_capital = notional_trading_capital
if base_currency is not arg_not_supplied:
config.base_currency = base_currency
system = futures_system(data=sim_data, config=config)
system._log = log
return system
def updated_buffered_positions(data: dataBlob, strategy_name: str, system: System):
log = data.log
data_optimal_positions = dataOptimalPositions(data)
list_of_instruments = system.get_instrument_list()
for instrument_code in list_of_instruments:
lower_buffer, upper_buffer = get_position_buffers_from_system(
system, instrument_code
)
position_entry = construct_position_entry(
data=data,
system=system,
instrument_code=instrument_code,
lower_position=lower_buffer,
upper_position=upper_buffer,
)
instrument_strategy = instrumentStrategy(
instrument_code=instrument_code, strategy_name=strategy_name
)
data_optimal_positions.update_optimal_position_for_instrument_strategy(
instrument_strategy=instrument_strategy, position_entry=position_entry
)
log.debug(
"New buffered positions %.3f %.3f"
% (position_entry.lower_position, position_entry.upper_position),
instrument_code=instrument_code,
)
def get_position_buffers_from_system(system: System, instrument_code: str):
buffers = system.portfolio.get_buffers_for_position(
instrument_code
) # get the upper and lower edges of the buffer
lower_buffer = buffers.iloc[-1].bot_pos
upper_buffer = buffers.iloc[-1].top_pos
return lower_buffer, upper_buffer
def construct_position_entry(
data: dataBlob,
system: System,
instrument_code: str,
lower_position: float,
upper_position: float,
) -> bufferedOptimalPositions:
diag_contracts = dataContracts(data)
reference_price = system.rawdata.get_daily_prices(instrument_code).iloc[-1]
reference_contract = diag_contracts.get_priced_contract_id(instrument_code)
position_entry = bufferedOptimalPositions(
date=datetime.datetime.now(),
lower_position=lower_position,
upper_position=upper_position,
reference_price=reference_price,
reference_contract=reference_contract,
)
return position_entry