forked from robcarver17/pysystemtrade
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtrade_limits.py
220 lines (173 loc) · 7.88 KB
/
trade_limits.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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
"""
We want to limit the number of trades we expect to do in a given period (usually a day, but could be longer if
eg going on holiday)
Limits per contract don't make sense, but it makes sense to limit (a) the number of times a given instrument
within a strategy can be traded and (b) the number of times an instrument can be traded, period.
"""
from dataclasses import dataclass
from syscore.exceptions import missingData
from sysdata.base_data import baseData
from syslogging.logger import *
from sysobjects.production.trade_limits import tradeLimit, listOfTradeLimits
from sysobjects.production.tradeable_object import instrumentStrategy
@dataclass
class instrumentStrategyKeyAndDays:
instrument_strategy_key: str
period_days: int
@classmethod
def from_trade_limit(instrumentStrategyKeyAndDays, trade_limit: tradeLimit):
return instrumentStrategyKeyAndDays(
trade_limit.instrument_strategy.key, trade_limit.period_days
)
class listOfInstrumentStrategyKeyAndDays(list):
def for_given_instrument_strategy(self, instrument_strategy: instrumentStrategy):
instrument_strategy_key = instrument_strategy.key
results = [
item
for item in self
if item.instrument_strategy_key == instrument_strategy_key
]
return listOfInstrumentStrategyKeyAndDays(results)
class tradeLimitData(baseData):
def __init__(self, log=get_logger("Overrides")):
super().__init__(log=log)
def no_limit(
self, instrument_strategy: instrumentStrategy, period_days: int
) -> tradeLimit:
return tradeLimit(
999999,
instrument_strategy,
period_days=period_days,
)
def what_trade_is_possible_for_instrument(
self, instrument_code: str, proposed_trade: int
) -> int:
combined_list = self.get_trade_limits_for_instrument(instrument_code)
possible_trade = combined_list.what_trade_is_possible(proposed_trade)
return possible_trade
def what_trade_is_possible_for_instrument_strategy(
self, instrument_strategy: instrumentStrategy, proposed_trade: int
) -> int:
combined_list = self._get_list_of_all_relevant_trade_limits(instrument_strategy)
possible_trade = combined_list.what_trade_is_possible(proposed_trade)
return possible_trade
def add_trade(self, instrument_strategy: instrumentStrategy, trade: int):
combined_list = self._get_list_of_all_relevant_trade_limits(instrument_strategy)
combined_list.add_trade(trade)
self._update_list_of_trade_limits(combined_list)
def remove_trade(self, instrument_strategy: instrumentStrategy, trade: int):
combined_list = self._get_list_of_all_relevant_trade_limits(instrument_strategy)
combined_list.remove_trade(trade)
self._update_list_of_trade_limits(combined_list)
def _get_list_of_all_relevant_trade_limits(
self, instrument_strategy: instrumentStrategy
) -> listOfTradeLimits:
instrument_trade_limits = self.get_trade_limits_for_instrument(
instrument_strategy.instrument_code
)
strategy_instrument_trade_limits = (
self.get_trade_limits_for_instrument_strategy(instrument_strategy)
)
combined_list = listOfTradeLimits(
instrument_trade_limits + strategy_instrument_trade_limits
)
return combined_list
def get_trade_limits_for_instrument(
self, instrument_code: str
) -> listOfTradeLimits:
instrument_strategy = instrument_strategy_for_instrument_only(instrument_code)
return listOfTradeLimits(
self.get_trade_limits_for_instrument_strategy(instrument_strategy)
)
def get_trade_limits_for_instrument_strategy(
self, instrument_strategy: instrumentStrategy
) -> listOfTradeLimits:
all_keys = self._get_all_limit_keys()
relevant_keys = all_keys.for_given_instrument_strategy(instrument_strategy)
trade_limits = [
self._get_trade_limit_object_from_isd_key(isd_key)
for isd_key in relevant_keys
]
return listOfTradeLimits(trade_limits)
def _update_list_of_trade_limits(self, list_of_trade_limits: list):
result = [
self._update_trade_limit_object(trade_limit_object)
for trade_limit_object in list_of_trade_limits
]
return result
def update_instrument_limit_with_new_limit(
self, instrument_code: str, period_days: int, new_limit: int
):
"""
self.update_instrument_strategy_limit_with_new_limit(
"", instrument_code, period_days, new_limit
)
"""
instrument_strategy = instrument_strategy_for_instrument_only(instrument_code)
self.update_instrument_strategy_limit_with_new_limit(
instrument_strategy, period_days, new_limit
)
def update_instrument_strategy_limit_with_new_limit(
self, instrument_strategy: instrumentStrategy, period_days: int, new_limit: int
):
trade_limit = self._get_trade_limit_object(instrument_strategy, period_days)
trade_limit.update_limit(new_limit)
self._update_trade_limit_object(trade_limit)
def reset_all_limits(self):
all_limits = self.get_all_limits()
for limit in all_limits:
self.reset_instrument_strategy_limit(
instrument_strategy=limit.instrument_strategy,
period_days=limit.period_days,
)
def reset_instrument_limit(self, instrument_code: str, period_days: int):
instrument_strategy = instrument_strategy_for_instrument_only(instrument_code)
self.reset_instrument_strategy_limit(instrument_strategy, period_days)
def reset_strategy_limit_all_instruments(
self, strategy_name: str, period_days: int
):
pass
def reset_instrument_strategy_limit(
self, instrument_strategy: instrumentStrategy, period_days: int
):
trade_limit = self._get_trade_limit_object(instrument_strategy, period_days)
trade_limit.reset()
self._update_trade_limit_object(trade_limit)
def get_all_limits(self) -> list:
all_keys = self._get_all_limit_keys()
all_limits = [
self._get_trade_limit_object_from_isd_key(key) for key in all_keys
]
return listOfTradeLimits(all_limits)
def _get_trade_limit_object_from_isd_key(
self, isd_key: instrumentStrategyKeyAndDays
) -> tradeLimit:
instrument_strategy = instrumentStrategy.from_key(
isd_key.instrument_strategy_key
)
period_days = isd_key.period_days
return self._get_trade_limit_object(instrument_strategy, period_days)
def _get_trade_limit_object(
self, instrument_strategy: instrumentStrategy, period_days: int
) -> tradeLimit:
try:
trade_limit_as_dict = self._get_trade_limit_as_dict_or_missing_data(
instrument_strategy, period_days
)
except missingData:
return self.no_limit(instrument_strategy, period_days)
trade_limit_object = tradeLimit.from_dict(trade_limit_as_dict)
return trade_limit_object
def _update_trade_limit_object(self, trade_limit_object):
trade_limit_as_dict = trade_limit_object.as_dict()
self._update_trade_limit_as_dict(trade_limit_as_dict)
def _get_trade_limit_as_dict_or_missing_data(
self, instrument_strategy: instrumentStrategy, period_days: int
) -> dict:
raise NotImplementedError
def _update_trade_limit_as_dict(self, trade_limit_object: dict):
raise NotImplementedError
def _get_all_limit_keys(self) -> listOfInstrumentStrategyKeyAndDays:
raise NotImplementedError
def instrument_strategy_for_instrument_only(instrument_code) -> instrumentStrategy:
return instrumentStrategy(strategy_name="", instrument_code=instrument_code)