tradingsystemsdata 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tradingsystemsdata/__init__.py +5 -0
- tradingsystemsdata/dollar_exits.py +348 -0
- tradingsystemsdata/graph_data.py +279 -0
- tradingsystemsdata/indicator_entries.py +1056 -0
- tradingsystemsdata/indicator_exits.py +980 -0
- tradingsystemsdata/ma_entries.py +371 -0
- tradingsystemsdata/marketdata.py +590 -0
- tradingsystemsdata/pnl.py +889 -0
- tradingsystemsdata/positions.py +562 -0
- tradingsystemsdata/reports.py +955 -0
- tradingsystemsdata/signals.py +587 -0
- tradingsystemsdata/systems.py +709 -0
- tradingsystemsdata/systems_params.py +324 -0
- tradingsystemsdata/targets.py +262 -0
- tradingsystemsdata/trades.py +304 -0
- tradingsystemsdata/utils.py +488 -0
- tradingsystemsdata/winloss.py +320 -0
- tradingsystemsdata-1.0.0.dist-info/LICENSE +21 -0
- tradingsystemsdata-1.0.0.dist-info/METADATA +71 -0
- tradingsystemsdata-1.0.0.dist-info/RECORD +22 -0
- tradingsystemsdata-1.0.0.dist-info/WHEEL +5 -0
- tradingsystemsdata-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Exit signals based on a dollar value.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
class DollarExit():
|
|
9
|
+
"""
|
|
10
|
+
Calculate dollar value based exit signals.
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def exit_dollar(
|
|
16
|
+
cls,
|
|
17
|
+
prices: pd.DataFrame,
|
|
18
|
+
trigger_value: pd.Series,
|
|
19
|
+
exit_level: str) -> tuple[pd.DataFrame, np.ndarray]:
|
|
20
|
+
"""
|
|
21
|
+
Calculate exit based on a dollar amount.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
prices : DataFrame
|
|
26
|
+
The OHLC data.
|
|
27
|
+
trigger_value : Series
|
|
28
|
+
The series to trigger exit.
|
|
29
|
+
trade_number : Series
|
|
30
|
+
Array of trade numbers.
|
|
31
|
+
end_of_day_position : Series
|
|
32
|
+
The close of day, long/short/flat position.
|
|
33
|
+
trade_high_price : Series
|
|
34
|
+
The high price of the trade.
|
|
35
|
+
trade_low_price : Series
|
|
36
|
+
The low price of the trade.
|
|
37
|
+
exit_level : Str
|
|
38
|
+
The type of exit strategy.
|
|
39
|
+
|
|
40
|
+
Returns
|
|
41
|
+
-------
|
|
42
|
+
prices : DataFrame
|
|
43
|
+
The OHLC data
|
|
44
|
+
exit : Series
|
|
45
|
+
Exit signals.
|
|
46
|
+
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
# Calculate exit signal based on a profit target
|
|
50
|
+
if exit_level == 'profit_target':
|
|
51
|
+
prices, exit_ = cls._exit_profit_target(
|
|
52
|
+
prices=prices,
|
|
53
|
+
trigger_value=trigger_value)
|
|
54
|
+
|
|
55
|
+
# Calculate exit signal based on a loss from entry price
|
|
56
|
+
elif exit_level == 'initial':
|
|
57
|
+
prices, exit_ = cls._exit_initial_dollar_loss(
|
|
58
|
+
prices=prices,
|
|
59
|
+
trigger_value=trigger_value)
|
|
60
|
+
|
|
61
|
+
# Calculate exit signal based on a breakeven level
|
|
62
|
+
elif exit_level == 'breakeven':
|
|
63
|
+
prices, exit_ = cls._exit_breakeven(
|
|
64
|
+
prices=prices,
|
|
65
|
+
trigger_value=trigger_value)
|
|
66
|
+
|
|
67
|
+
# Calculate exit signal based on a trailing stop referencing the close
|
|
68
|
+
elif exit_level == 'trail_close':
|
|
69
|
+
prices, exit_ = cls._exit_trailing(
|
|
70
|
+
prices=prices,
|
|
71
|
+
trigger_value=trigger_value)
|
|
72
|
+
|
|
73
|
+
# Calculate exit signal based on a trailing stop referencing the
|
|
74
|
+
# high/low
|
|
75
|
+
elif exit_level == 'trail_high_low':
|
|
76
|
+
prices, exit_ = cls._exit_trailing(
|
|
77
|
+
prices=prices,
|
|
78
|
+
trigger_value=trigger_value)
|
|
79
|
+
|
|
80
|
+
return prices, exit_
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def _exit_profit_target(
|
|
85
|
+
prices: pd.DataFrame,
|
|
86
|
+
trigger_value: pd.Series) -> tuple[pd.DataFrame, np.ndarray]:
|
|
87
|
+
"""
|
|
88
|
+
Calculate exit based on a profit target.
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
prices : DataFrame
|
|
93
|
+
The OHLC data.
|
|
94
|
+
trigger_value : Series
|
|
95
|
+
The series to trigger exit.
|
|
96
|
+
trade_number : Series
|
|
97
|
+
Array of trade numbers.
|
|
98
|
+
end_of_day_position : Series
|
|
99
|
+
The close of day, long/short/flat position.
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
prices : DataFrame
|
|
104
|
+
The OHLC data
|
|
105
|
+
profit_target_exit : Series
|
|
106
|
+
The exit signals.
|
|
107
|
+
|
|
108
|
+
"""
|
|
109
|
+
trade_number = prices['raw_trade_number']
|
|
110
|
+
end_of_day_position = prices['raw_end_of_day_position']
|
|
111
|
+
|
|
112
|
+
# Create an empty array to store the signals
|
|
113
|
+
profit_target_exit = np.array([0]*len(prices))
|
|
114
|
+
|
|
115
|
+
# For each row in the data
|
|
116
|
+
for row in range(1, len(prices)):
|
|
117
|
+
|
|
118
|
+
# If there is a trade on
|
|
119
|
+
if trade_number.iloc[row] != 0:
|
|
120
|
+
|
|
121
|
+
# If there is a long position
|
|
122
|
+
if end_of_day_position.iloc[row] > 0:
|
|
123
|
+
|
|
124
|
+
# If the close is greater than the trigger value
|
|
125
|
+
if prices['Close'].iloc[row] > trigger_value.iloc[row]:
|
|
126
|
+
|
|
127
|
+
# Set the exit signal to -1
|
|
128
|
+
profit_target_exit[row] = -1
|
|
129
|
+
|
|
130
|
+
# If there is a short position
|
|
131
|
+
elif end_of_day_position.iloc[row] < 0:
|
|
132
|
+
|
|
133
|
+
# If the close is less than the trigger value
|
|
134
|
+
if prices['Close'].iloc[row] < trigger_value.iloc[row]:
|
|
135
|
+
|
|
136
|
+
# Set the exit signal to 1
|
|
137
|
+
profit_target_exit[row] = 1
|
|
138
|
+
|
|
139
|
+
else:
|
|
140
|
+
# Set the exit signal to 0
|
|
141
|
+
profit_target_exit[row] = 0
|
|
142
|
+
|
|
143
|
+
return prices, profit_target_exit
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def _exit_initial_dollar_loss(
|
|
148
|
+
prices: pd.DataFrame,
|
|
149
|
+
trigger_value: pd.Series) -> tuple[pd.DataFrame, np.ndarray]:
|
|
150
|
+
"""
|
|
151
|
+
Calculate exit based on a given loss from the entry point.
|
|
152
|
+
|
|
153
|
+
Parameters
|
|
154
|
+
----------
|
|
155
|
+
prices : DataFrame
|
|
156
|
+
The OHLC data.
|
|
157
|
+
trigger_value : Series
|
|
158
|
+
The series to trigger exit.
|
|
159
|
+
trade_number : Series
|
|
160
|
+
Array of trade numbers.
|
|
161
|
+
end_of_day_position : Series
|
|
162
|
+
The close of day, long/short/flat position.
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
prices : DataFrame
|
|
167
|
+
The OHLC data.
|
|
168
|
+
initial_dollar_loss_exit : Series
|
|
169
|
+
The exit signals.
|
|
170
|
+
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
trade_number = prices['raw_trade_number']
|
|
174
|
+
end_of_day_position = prices['raw_end_of_day_position']
|
|
175
|
+
|
|
176
|
+
# Create an empty array to store the signals
|
|
177
|
+
initial_dollar_loss_exit = np.array([0]*len(prices))
|
|
178
|
+
|
|
179
|
+
# For each row in the data
|
|
180
|
+
for row in range(1, len(prices)):
|
|
181
|
+
|
|
182
|
+
# If there is a trade on
|
|
183
|
+
if trade_number.iloc[row] != 0:
|
|
184
|
+
|
|
185
|
+
# If there is a long position
|
|
186
|
+
if end_of_day_position.iloc[row] > 0:
|
|
187
|
+
|
|
188
|
+
# If the close is less than the trigger value
|
|
189
|
+
if prices['Close'].iloc[row] < trigger_value.iloc[row]:
|
|
190
|
+
|
|
191
|
+
# Set the exit signal to -1
|
|
192
|
+
initial_dollar_loss_exit[row] = -1
|
|
193
|
+
|
|
194
|
+
# If there is a short position
|
|
195
|
+
elif end_of_day_position.iloc[row] < 0:
|
|
196
|
+
|
|
197
|
+
# If the close is greater than the trigger value
|
|
198
|
+
if prices['Close'].iloc[row] > trigger_value.iloc[row]:
|
|
199
|
+
|
|
200
|
+
# Set the exit signal to 1
|
|
201
|
+
initial_dollar_loss_exit[row] = 1
|
|
202
|
+
|
|
203
|
+
else:
|
|
204
|
+
# Set the exit signal to 0
|
|
205
|
+
initial_dollar_loss_exit[row] = 0
|
|
206
|
+
|
|
207
|
+
return prices, initial_dollar_loss_exit
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@staticmethod
|
|
211
|
+
def _exit_breakeven(
|
|
212
|
+
prices: pd.DataFrame,
|
|
213
|
+
trigger_value: pd.Series) -> tuple[pd.DataFrame, np.ndarray]:
|
|
214
|
+
"""
|
|
215
|
+
Calculate exit based on passing a breakeven threshold.
|
|
216
|
+
|
|
217
|
+
Parameters
|
|
218
|
+
----------
|
|
219
|
+
prices : DataFrame
|
|
220
|
+
The OHLC data.
|
|
221
|
+
trigger_value : Series
|
|
222
|
+
The series to trigger exit.
|
|
223
|
+
trade_number : Series
|
|
224
|
+
Array of trade numbers.
|
|
225
|
+
end_of_day_position : Series
|
|
226
|
+
The close of day, long/short/flat position.
|
|
227
|
+
trade_high_price : Series
|
|
228
|
+
The high price of the trade.
|
|
229
|
+
trade_low_price : Series
|
|
230
|
+
The low price of the trade.
|
|
231
|
+
|
|
232
|
+
Returns
|
|
233
|
+
-------
|
|
234
|
+
prices : DataFrame
|
|
235
|
+
The OHLC data.
|
|
236
|
+
breakeven_exit : Series
|
|
237
|
+
The exit signals.
|
|
238
|
+
|
|
239
|
+
"""
|
|
240
|
+
|
|
241
|
+
trade_number = prices['raw_trade_number']
|
|
242
|
+
end_of_day_position = prices['raw_end_of_day_position']
|
|
243
|
+
trade_high_price = prices['raw_trade_high_price']
|
|
244
|
+
trade_low_price = prices['raw_trade_low_price']
|
|
245
|
+
|
|
246
|
+
# Create an empty array to store the signals
|
|
247
|
+
breakeven_exit = np.array([0.0]*len(prices))
|
|
248
|
+
|
|
249
|
+
# For each row in the data
|
|
250
|
+
for row in range(1, len(prices)):
|
|
251
|
+
|
|
252
|
+
# If there is a trade on
|
|
253
|
+
if trade_number.iloc[row] != 0:
|
|
254
|
+
|
|
255
|
+
# If there is a long position
|
|
256
|
+
if end_of_day_position.iloc[row] > 0:
|
|
257
|
+
|
|
258
|
+
# If the high price of the trade is greater than the
|
|
259
|
+
# trigger value
|
|
260
|
+
if trade_high_price.iloc[row] > trigger_value.iloc[row]:
|
|
261
|
+
|
|
262
|
+
# If the close is less than the trigger value
|
|
263
|
+
if prices['Close'].iloc[row] < trigger_value.iloc[row]:
|
|
264
|
+
|
|
265
|
+
# Set the exit signal to -1
|
|
266
|
+
breakeven_exit[row] = -1
|
|
267
|
+
|
|
268
|
+
# If there is a short position
|
|
269
|
+
elif end_of_day_position.iloc[row] < 0:
|
|
270
|
+
|
|
271
|
+
# If the low price of the trade is less than the
|
|
272
|
+
# trigger value
|
|
273
|
+
if trade_low_price.iloc[row] < trigger_value.iloc[row]:
|
|
274
|
+
|
|
275
|
+
# If the close is greater than the trigger value
|
|
276
|
+
if prices['Close'].iloc[row] > trigger_value.iloc[row]:
|
|
277
|
+
|
|
278
|
+
# Set the exit signal to 1
|
|
279
|
+
breakeven_exit[row] = 1
|
|
280
|
+
else:
|
|
281
|
+
# Set the exit signal to 0
|
|
282
|
+
breakeven_exit[row] = 0
|
|
283
|
+
|
|
284
|
+
return prices, breakeven_exit
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
@staticmethod
|
|
288
|
+
def _exit_trailing(
|
|
289
|
+
prices: pd.DataFrame,
|
|
290
|
+
trigger_value: pd.Series) -> tuple[pd.DataFrame, np.ndarray]:
|
|
291
|
+
"""
|
|
292
|
+
Calculate exit based on a trailing stop.
|
|
293
|
+
|
|
294
|
+
Parameters
|
|
295
|
+
----------
|
|
296
|
+
prices : DataFrame
|
|
297
|
+
The OHLC data.
|
|
298
|
+
trigger_value : Series
|
|
299
|
+
The series to trigger exit.
|
|
300
|
+
trade_number : Series
|
|
301
|
+
Array of trade numbers.
|
|
302
|
+
end_of_day_position : Series
|
|
303
|
+
The close of day, long/short/flat position.
|
|
304
|
+
|
|
305
|
+
Returns
|
|
306
|
+
-------
|
|
307
|
+
prices : DataFrame
|
|
308
|
+
The OHLC data.
|
|
309
|
+
trailing_exit : Series
|
|
310
|
+
The exit signals.
|
|
311
|
+
|
|
312
|
+
"""
|
|
313
|
+
|
|
314
|
+
trade_number = prices['raw_trade_number']
|
|
315
|
+
end_of_day_position = prices['raw_end_of_day_position']
|
|
316
|
+
|
|
317
|
+
# Create an empty array to store the signals
|
|
318
|
+
trailing_exit = np.array([0.0]*len(prices))
|
|
319
|
+
|
|
320
|
+
# For each row in the data
|
|
321
|
+
for row in range(1, len(prices)):
|
|
322
|
+
|
|
323
|
+
# If there is a trade on
|
|
324
|
+
if trade_number.iloc[row] != 0:
|
|
325
|
+
|
|
326
|
+
# If there is a long position
|
|
327
|
+
if end_of_day_position.iloc[row] > 0:
|
|
328
|
+
|
|
329
|
+
# If the close is less than the trigger value
|
|
330
|
+
if prices['Close'].iloc[row] < trigger_value.iloc[row]:
|
|
331
|
+
|
|
332
|
+
# Set the exit signal to -1
|
|
333
|
+
trailing_exit[row] = -1
|
|
334
|
+
|
|
335
|
+
# If there is a short position
|
|
336
|
+
elif end_of_day_position.iloc[row] < 0:
|
|
337
|
+
|
|
338
|
+
# If the close is greater than the trigger value
|
|
339
|
+
if prices['Close'].iloc[row] > trigger_value.iloc[row]:
|
|
340
|
+
|
|
341
|
+
# Set the exit signal to 1
|
|
342
|
+
trailing_exit[row] = 1
|
|
343
|
+
|
|
344
|
+
else:
|
|
345
|
+
# Set the exit signal to 0
|
|
346
|
+
trailing_exit[row] = 0
|
|
347
|
+
|
|
348
|
+
return prices, trailing_exit
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Graph the performance of the trading strategy
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
# pylint: disable=unbalanced-tuple-unpacking
|
|
8
|
+
# pylint: disable=no-else-return
|
|
9
|
+
|
|
10
|
+
class GraphData():
|
|
11
|
+
"""
|
|
12
|
+
Class of functions used to return data to graph trading system performance
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def graph_variables(
|
|
18
|
+
prices: pd.DataFrame,
|
|
19
|
+
entry_type: str,
|
|
20
|
+
entry_signal_indicators: dict | None = None) -> dict:
|
|
21
|
+
"""
|
|
22
|
+
Create graph initialization variables
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
dates : Pandas Series
|
|
27
|
+
The dates to plot on the x-axis.
|
|
28
|
+
price : Pandas Series
|
|
29
|
+
Closing Prices.
|
|
30
|
+
equity : Pandas Series
|
|
31
|
+
Daily Mark to Market Equity level.
|
|
32
|
+
cumsig : Pandas Series
|
|
33
|
+
The cumulative buy / sell signal.
|
|
34
|
+
lower_bound : Pandas Series
|
|
35
|
+
Lower point to set where trading signals are plotted from.
|
|
36
|
+
upper_bound : Pandas Series
|
|
37
|
+
Upper point to set where trading signals are plotted from.
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
# Dictionary to store default params
|
|
42
|
+
graph_params = {}
|
|
43
|
+
|
|
44
|
+
# Set the dates to the index of the main DataFrame
|
|
45
|
+
graph_params['dates'] = prices.index
|
|
46
|
+
|
|
47
|
+
# Closing Prices
|
|
48
|
+
graph_params['price'] = prices['Close']
|
|
49
|
+
|
|
50
|
+
# MTM Equity
|
|
51
|
+
graph_params['equity'] = prices['mtm_equity']
|
|
52
|
+
|
|
53
|
+
# Cumulative sum of the combined entry, exit and stop signal
|
|
54
|
+
graph_params['cumsig'] = prices['combined_signal'].cumsum()
|
|
55
|
+
|
|
56
|
+
# The lower and upper bounds are used in setting where the trade
|
|
57
|
+
# signals are plotted on the price chart
|
|
58
|
+
# If the entry is a channel breakout
|
|
59
|
+
if entry_type == 'channel_breakout':
|
|
60
|
+
|
|
61
|
+
# Set the lower bound as rolling low close prices
|
|
62
|
+
graph_params['lower_bound'] = prices[
|
|
63
|
+
entry_signal_indicators[entry_type][0]]
|
|
64
|
+
|
|
65
|
+
# Set the upper bound as rolling high close prices
|
|
66
|
+
graph_params['upper_bound'] = prices[
|
|
67
|
+
entry_signal_indicators[entry_type][1]]
|
|
68
|
+
|
|
69
|
+
elif entry_type in ['2ma', '3ma', '4ma']:
|
|
70
|
+
|
|
71
|
+
# Set the lower bound as the lowest of the moving average values
|
|
72
|
+
# and the price
|
|
73
|
+
graph_params['lower_bound'] = prices['min_ma']
|
|
74
|
+
|
|
75
|
+
# Set the upper bound as the highest of the moving average values
|
|
76
|
+
# and the price
|
|
77
|
+
graph_params['upper_bound'] = prices['max_ma']
|
|
78
|
+
|
|
79
|
+
# Otherwise
|
|
80
|
+
else:
|
|
81
|
+
# Set the upper and lower bounds to the closing price
|
|
82
|
+
graph_params['lower_bound'] = graph_params['price']
|
|
83
|
+
graph_params['upper_bound'] = graph_params['price']
|
|
84
|
+
|
|
85
|
+
return graph_params
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def _bar_color(
|
|
90
|
+
price_data: pd.Series,
|
|
91
|
+
color1: str,
|
|
92
|
+
color2: str) -> np.ndarray:
|
|
93
|
+
"""
|
|
94
|
+
Set barchart color to green if positive and red if negative.
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
price_data : Series
|
|
99
|
+
Price data.
|
|
100
|
+
color1 : Str
|
|
101
|
+
Color for positive data.
|
|
102
|
+
color2 : Str
|
|
103
|
+
Color for negative data.
|
|
104
|
+
|
|
105
|
+
Returns
|
|
106
|
+
-------
|
|
107
|
+
Series
|
|
108
|
+
Series of colors for each data point.
|
|
109
|
+
|
|
110
|
+
"""
|
|
111
|
+
return np.where(price_data.values > 0, color1, color2).T
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def create_signals(
|
|
116
|
+
cls,
|
|
117
|
+
prices: pd.DataFrame,
|
|
118
|
+
graph_params: dict) -> dict:
|
|
119
|
+
"""
|
|
120
|
+
Create trade signals to be plotted on main price chart
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
cumsig : Pandas Series
|
|
125
|
+
The cumulative buy / sell signal.
|
|
126
|
+
lower_bound : Pandas Series
|
|
127
|
+
Lower point to set where trading signals are plotted from.
|
|
128
|
+
upper_bound : Pandas Series
|
|
129
|
+
Upper point to set where trading signals are plotted from.
|
|
130
|
+
|
|
131
|
+
Returns
|
|
132
|
+
-------
|
|
133
|
+
signal_dict : Dict
|
|
134
|
+
Dictionary containing the trade signal details.
|
|
135
|
+
|
|
136
|
+
"""
|
|
137
|
+
# Create empty dictionary
|
|
138
|
+
signal_dict = {}
|
|
139
|
+
signal_dict['data_markers'] = {}
|
|
140
|
+
|
|
141
|
+
upper, lower = cls._set_upper_lower(graph_params=graph_params)
|
|
142
|
+
|
|
143
|
+
buy_sell_distance = 0.10 * (upper - lower) # 0.07
|
|
144
|
+
flat_distance = 0.15 * (upper - lower) # 0.1
|
|
145
|
+
|
|
146
|
+
# Buy signal to go long is where the current cumulative signal is to be
|
|
147
|
+
# long when yesterday it was flat
|
|
148
|
+
signal_dict['buy_long_signals'] = (
|
|
149
|
+
(graph_params['cumsig'] == 1)
|
|
150
|
+
& (graph_params['cumsig'].shift() != 1))
|
|
151
|
+
|
|
152
|
+
# Place the marker at the specified distance below the lower bound
|
|
153
|
+
signal_dict['buy_long_marker'] = (
|
|
154
|
+
graph_params['lower_bound']
|
|
155
|
+
* signal_dict['buy_long_signals']
|
|
156
|
+
- buy_sell_distance)
|
|
157
|
+
#- graph_params['lower_bound'].max()*buy_sell_distance)
|
|
158
|
+
|
|
159
|
+
signal_dict['buy_long_marker'] = signal_dict[
|
|
160
|
+
'buy_long_marker'][signal_dict['buy_long_signals']]
|
|
161
|
+
|
|
162
|
+
# Add raw signal position for use in api
|
|
163
|
+
signal_dict['data_markers']['openLong'] = (
|
|
164
|
+
graph_params['lower_bound']
|
|
165
|
+
* signal_dict['buy_long_signals']
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
signal_dict['data_markers']['openLong'] = signal_dict['data_markers'][
|
|
169
|
+
'openLong'][signal_dict['buy_long_signals']]
|
|
170
|
+
|
|
171
|
+
# Set the dates for the buy long signals
|
|
172
|
+
signal_dict['buy_long_dates'] = prices.index[
|
|
173
|
+
signal_dict['buy_long_signals']]
|
|
174
|
+
|
|
175
|
+
signal_dict['data_markers']['openLongDates'] = signal_dict['buy_long_dates']
|
|
176
|
+
|
|
177
|
+
# Buy signal to go flat is where the current cumulative signal is to be
|
|
178
|
+
# flat when yesterday it was short
|
|
179
|
+
signal_dict['buy_flat_signals'] = (
|
|
180
|
+
(graph_params['cumsig'] == 0)
|
|
181
|
+
& (graph_params['cumsig'].shift() == -1))
|
|
182
|
+
|
|
183
|
+
# Place the marker at the specified distance below the lower bound
|
|
184
|
+
signal_dict['buy_flat_marker'] = (
|
|
185
|
+
graph_params['lower_bound']
|
|
186
|
+
* signal_dict['buy_flat_signals']
|
|
187
|
+
- flat_distance)
|
|
188
|
+
#- graph_params['lower_bound'].max()*flat_distance)
|
|
189
|
+
|
|
190
|
+
signal_dict['buy_flat_marker'] = signal_dict[
|
|
191
|
+
'buy_flat_marker'][signal_dict['buy_flat_signals']]
|
|
192
|
+
|
|
193
|
+
# Add raw signal position for use in api
|
|
194
|
+
signal_dict['data_markers']['closeShort'] = (
|
|
195
|
+
graph_params['lower_bound']
|
|
196
|
+
* signal_dict['buy_flat_signals']
|
|
197
|
+
)
|
|
198
|
+
signal_dict['data_markers']['closeShort'] = signal_dict['data_markers']['closeShort'][signal_dict['buy_flat_signals']]
|
|
199
|
+
|
|
200
|
+
# Set the dates for the buy flat signals
|
|
201
|
+
signal_dict['buy_flat_dates'] = prices.index[
|
|
202
|
+
signal_dict['buy_flat_signals']]
|
|
203
|
+
|
|
204
|
+
signal_dict['data_markers']['closeShortDates'] = signal_dict['buy_flat_dates']
|
|
205
|
+
|
|
206
|
+
# Sell signal to go flat is where the current cumulative signal is to
|
|
207
|
+
# be flat when yesterday it was long
|
|
208
|
+
signal_dict['sell_flat_signals'] = (
|
|
209
|
+
(graph_params['cumsig'] == 0)
|
|
210
|
+
& (graph_params['cumsig'].shift() == 1))
|
|
211
|
+
|
|
212
|
+
# Place the marker at the specified distance above the upper bound
|
|
213
|
+
signal_dict['sell_flat_marker'] = (
|
|
214
|
+
graph_params['upper_bound']
|
|
215
|
+
* signal_dict['sell_flat_signals']
|
|
216
|
+
+ flat_distance)
|
|
217
|
+
#+ graph_params['upper_bound'].max()*flat_distance)
|
|
218
|
+
|
|
219
|
+
signal_dict['sell_flat_marker'] = signal_dict[
|
|
220
|
+
'sell_flat_marker'][signal_dict['sell_flat_signals']]
|
|
221
|
+
|
|
222
|
+
# Add raw signal position for use in api
|
|
223
|
+
signal_dict['data_markers']['closeLong'] = (
|
|
224
|
+
graph_params['upper_bound']
|
|
225
|
+
* signal_dict['sell_flat_signals']
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
signal_dict['data_markers']['closeLong'] = signal_dict['data_markers']['closeLong'][signal_dict['sell_flat_signals']]
|
|
229
|
+
|
|
230
|
+
# Set the dates for the sell flat signals
|
|
231
|
+
signal_dict['sell_flat_dates'] = prices.index[
|
|
232
|
+
signal_dict['sell_flat_signals']]
|
|
233
|
+
|
|
234
|
+
signal_dict['data_markers']['closeLongDates'] = signal_dict['sell_flat_dates']
|
|
235
|
+
|
|
236
|
+
# Set the dates for the sell short signals
|
|
237
|
+
signal_dict['sell_short_signals'] = (
|
|
238
|
+
(graph_params['cumsig'] == -1)
|
|
239
|
+
& (graph_params['cumsig'].shift() != -1))
|
|
240
|
+
|
|
241
|
+
# Place the marker at the specified distance above the upper bound
|
|
242
|
+
signal_dict['sell_short_marker'] = (
|
|
243
|
+
graph_params['upper_bound']
|
|
244
|
+
* signal_dict['sell_short_signals']
|
|
245
|
+
+ buy_sell_distance)
|
|
246
|
+
#+ graph_params['upper_bound'].max()*buy_sell_distance)
|
|
247
|
+
|
|
248
|
+
signal_dict['sell_short_marker'] = signal_dict[
|
|
249
|
+
'sell_short_marker'][signal_dict['sell_short_signals']]
|
|
250
|
+
|
|
251
|
+
# Add raw signal position for use in api
|
|
252
|
+
signal_dict['data_markers']['openShort'] = (
|
|
253
|
+
graph_params['upper_bound']
|
|
254
|
+
* signal_dict['sell_short_signals']
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
signal_dict['data_markers']['openShort'] = signal_dict['data_markers']['openShort'][signal_dict['sell_short_signals']]
|
|
258
|
+
|
|
259
|
+
# Set the dates for the sell short signals
|
|
260
|
+
signal_dict['sell_short_dates'] = prices.index[
|
|
261
|
+
signal_dict['sell_short_signals']]
|
|
262
|
+
|
|
263
|
+
signal_dict['data_markers']['openShortDates'] = signal_dict['sell_short_dates']
|
|
264
|
+
|
|
265
|
+
return signal_dict
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
@staticmethod
|
|
269
|
+
def _set_upper_lower(
|
|
270
|
+
graph_params: dict) -> tuple[float, float]:
|
|
271
|
+
# Set upper to the max of the upper bound and lower to the lowest
|
|
272
|
+
# non-zero value of the lower bound, stripping zeros and nan values
|
|
273
|
+
|
|
274
|
+
upper = graph_params['upper_bound'][
|
|
275
|
+
graph_params['upper_bound'] != 0].dropna().max()
|
|
276
|
+
lower = graph_params['lower_bound'][
|
|
277
|
+
graph_params['lower_bound'] != 0].dropna().min()
|
|
278
|
+
|
|
279
|
+
return upper, lower
|