trendvisdata 1.0.4__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.
- trendvisdata/__init__.py +5 -0
- trendvisdata/chart_data.py +400 -0
- trendvisdata/chart_prep.py +637 -0
- trendvisdata/market_data.py +541 -0
- trendvisdata/sector_mappings.py +666 -0
- trendvisdata/trend.py +316 -0
- trendvisdata/trend_data.py +785 -0
- trendvisdata/trend_params.py +197 -0
- trendvisdata-1.0.4.dist-info/LICENSE +21 -0
- trendvisdata-1.0.4.dist-info/METADATA +29 -0
- trendvisdata-1.0.4.dist-info/RECORD +13 -0
- trendvisdata-1.0.4.dist-info/WHEEL +5 -0
- trendvisdata-1.0.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Prepare data for charts and graphs
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import copy
|
|
7
|
+
import math
|
|
8
|
+
import pandas as pd
|
|
9
|
+
|
|
10
|
+
class Formatting():
|
|
11
|
+
"""
|
|
12
|
+
Various data formatting methods for graphing
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
@staticmethod
|
|
16
|
+
def get_chart_title(params: dict) -> str:
|
|
17
|
+
"""
|
|
18
|
+
Create title label for market chart
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
norm : Bool
|
|
23
|
+
Whether the prices have been normalised.
|
|
24
|
+
trend : Str
|
|
25
|
+
The type / direction of the trend.
|
|
26
|
+
days : Int
|
|
27
|
+
The number of days price history.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
charttitle : Str
|
|
32
|
+
The chart title label.
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
norm = params['norm']
|
|
36
|
+
trend = params['trend']
|
|
37
|
+
days = params['days']
|
|
38
|
+
|
|
39
|
+
# Update chart title based on whether the data is normalized
|
|
40
|
+
# and the chosen trend type to display
|
|
41
|
+
if norm:
|
|
42
|
+
if trend == 'up':
|
|
43
|
+
chart_title = ("Up Trending Markets"
|
|
44
|
+
+" - Relative Return Over Last "
|
|
45
|
+
+str(days)+' Trading Days')
|
|
46
|
+
|
|
47
|
+
if trend == 'down':
|
|
48
|
+
chart_title = ("Down Trending Markets"
|
|
49
|
+
+" - Relative Return Over Last "
|
|
50
|
+
+str(days)+' Trading Days')
|
|
51
|
+
|
|
52
|
+
if trend == 'strong':
|
|
53
|
+
chart_title = ("Most Strongly Trending Markets"
|
|
54
|
+
+" - Relative Return Over Last "
|
|
55
|
+
+str(days)+' Trading Days')
|
|
56
|
+
|
|
57
|
+
if trend == 'neutral':
|
|
58
|
+
chart_title = ("Neutral Trending Markets"
|
|
59
|
+
+" - Relative Return Over Last "
|
|
60
|
+
+str(days)+' Trading Days')
|
|
61
|
+
|
|
62
|
+
if trend == 'all':
|
|
63
|
+
chart_title = ("Most Strongly and Neutral Trending"
|
|
64
|
+
+" Markets - Price Over Last "
|
|
65
|
+
+str(days)+' Trading Days')
|
|
66
|
+
|
|
67
|
+
else:
|
|
68
|
+
if trend == 'up':
|
|
69
|
+
chart_title = ("Up Trending Markets"
|
|
70
|
+
+" - Price Over Last "
|
|
71
|
+
+str(days)+' Trading Days')
|
|
72
|
+
|
|
73
|
+
if trend == 'down':
|
|
74
|
+
chart_title = ("Down Trending Markets"
|
|
75
|
+
+" - Price Over Last "
|
|
76
|
+
+str(days)+' Trading Days')
|
|
77
|
+
|
|
78
|
+
if trend == 'strong':
|
|
79
|
+
chart_title = ("Most Strongly Trending Markets"
|
|
80
|
+
+" - Price Over Last "
|
|
81
|
+
+str(days)+' Trading Days')
|
|
82
|
+
|
|
83
|
+
if trend == 'neutral':
|
|
84
|
+
chart_title = ("Neutral Trending Markets"
|
|
85
|
+
+" - Price Over Last "
|
|
86
|
+
+str(days)+' Trading Days')
|
|
87
|
+
|
|
88
|
+
if trend == 'all':
|
|
89
|
+
chart_title = ("Most Strongly and Neutral Trending"
|
|
90
|
+
+" Markets - Price Over Last "
|
|
91
|
+
+str(days)+' Trading Days')
|
|
92
|
+
|
|
93
|
+
chart_title = str(chart_title)
|
|
94
|
+
|
|
95
|
+
chart_title = chart_title+' - '+params['end_date']
|
|
96
|
+
|
|
97
|
+
return chart_title
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def create_mkt_dims(params: dict) -> dict:
|
|
102
|
+
"""
|
|
103
|
+
Create a tuple giving the height and width of the market chart
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
----------
|
|
107
|
+
mkts : Int
|
|
108
|
+
Number of markets to chart.
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
chart_dimensions : Tuple
|
|
113
|
+
Tuple of height, width for market chart.
|
|
114
|
+
|
|
115
|
+
"""
|
|
116
|
+
mkts = params['chart_mkts']
|
|
117
|
+
|
|
118
|
+
if mkts % 5 == 0:
|
|
119
|
+
width = 5
|
|
120
|
+
|
|
121
|
+
elif mkts % 4 == 0:
|
|
122
|
+
width = 4
|
|
123
|
+
|
|
124
|
+
elif mkts < 20 and mkts % 3 == 0:
|
|
125
|
+
width = 3
|
|
126
|
+
|
|
127
|
+
elif (mkts+1) % 5 == 0:
|
|
128
|
+
width = 5
|
|
129
|
+
|
|
130
|
+
elif (mkts+1) % 4 == 0:
|
|
131
|
+
width = 4
|
|
132
|
+
|
|
133
|
+
elif mkts < 20 and (mkts+1) % 3 == 0:
|
|
134
|
+
width = 3
|
|
135
|
+
|
|
136
|
+
else:
|
|
137
|
+
width = 5
|
|
138
|
+
|
|
139
|
+
height = math.ceil(mkts/width)
|
|
140
|
+
params['chart_dimensions'] = (height, width)
|
|
141
|
+
|
|
142
|
+
return params
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@classmethod
|
|
146
|
+
def create_normalized_data(
|
|
147
|
+
cls,
|
|
148
|
+
params: dict,
|
|
149
|
+
tables: dict,
|
|
150
|
+
flag: str) -> pd.DataFrame:
|
|
151
|
+
"""
|
|
152
|
+
Create a subset of chart_prep dataset normalized to start from
|
|
153
|
+
100 for the specified history window
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
params : Dict
|
|
158
|
+
mkts : Int
|
|
159
|
+
Number of markets to chart. The default is 5.
|
|
160
|
+
trend : Str
|
|
161
|
+
Flag to select most or least trending markets.
|
|
162
|
+
Select from: 'up' - strongly trending upwards,
|
|
163
|
+
'down - strongly trending downwards,
|
|
164
|
+
'neutral' - weak trend,
|
|
165
|
+
'strong' - up and down trends,
|
|
166
|
+
'all' - up down and weak trends
|
|
167
|
+
The default is 'strong' which displays both up-trending
|
|
168
|
+
and down-trending markets.
|
|
169
|
+
days : Int
|
|
170
|
+
Number of days of history. The default is 60.
|
|
171
|
+
tables : Dict
|
|
172
|
+
Dictionary of key tables.
|
|
173
|
+
|
|
174
|
+
Returns
|
|
175
|
+
-------
|
|
176
|
+
tenor : DataFrame
|
|
177
|
+
DataFrame of closing prices, normalized for a given historic
|
|
178
|
+
window
|
|
179
|
+
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
chart_data = cls._create_chart_data(
|
|
183
|
+
params=params,
|
|
184
|
+
tables=tables,
|
|
185
|
+
flag=flag
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Copy the selected number of days history from the input
|
|
189
|
+
# DataFrame
|
|
190
|
+
tenor = copy.deepcopy(chart_data[-params['days']:])
|
|
191
|
+
|
|
192
|
+
# Normalize the closing price of each ticker to start from 100
|
|
193
|
+
# at the beginning of the history window
|
|
194
|
+
for ticker in tenor.columns:
|
|
195
|
+
tenor[ticker] = tenor[ticker].div(tenor[ticker].iloc[0]).mul(100)
|
|
196
|
+
|
|
197
|
+
return tenor
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@classmethod
|
|
201
|
+
def _create_chart_data(
|
|
202
|
+
cls,
|
|
203
|
+
params: dict,
|
|
204
|
+
tables: dict,
|
|
205
|
+
flag: str) -> pd.DataFrame:
|
|
206
|
+
"""
|
|
207
|
+
Create a time series of closing prices for selected markets.
|
|
208
|
+
|
|
209
|
+
Parameters
|
|
210
|
+
----------
|
|
211
|
+
params : Dict
|
|
212
|
+
mkts : Int
|
|
213
|
+
Number of markets to chart. The default is 5.
|
|
214
|
+
trend : Str
|
|
215
|
+
Flag to select most or least trending markets.
|
|
216
|
+
Select from: 'up' - strongly trending upwards,
|
|
217
|
+
'down - strongly trending downwards,
|
|
218
|
+
'neutral' - weak trend,
|
|
219
|
+
'strong' - up and down trends,
|
|
220
|
+
'all' - up down and weak trends
|
|
221
|
+
The default is 'strong' which displays both up-trending
|
|
222
|
+
and down-trending markets.
|
|
223
|
+
tables : Dict
|
|
224
|
+
Dictionary of key tables.
|
|
225
|
+
|
|
226
|
+
Returns
|
|
227
|
+
-------
|
|
228
|
+
chart_data : DataFrame
|
|
229
|
+
DataFrame of closing prices of tickers selected by trend
|
|
230
|
+
strength.
|
|
231
|
+
|
|
232
|
+
"""
|
|
233
|
+
if flag == 'Unfiltered':
|
|
234
|
+
table = tables['barometer']
|
|
235
|
+
elif flag == 'High Returns':
|
|
236
|
+
table = tables['return_barometer']
|
|
237
|
+
else:
|
|
238
|
+
table = tables['sectors'][flag]
|
|
239
|
+
|
|
240
|
+
data_list = cls.create_data_list(
|
|
241
|
+
params,
|
|
242
|
+
table,
|
|
243
|
+
market_chart=False,
|
|
244
|
+
num_charts=None
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
# Create a new DataFrame
|
|
248
|
+
chart_data = pd.DataFrame()
|
|
249
|
+
|
|
250
|
+
# For each ticker in the list of selected tickers, add the
|
|
251
|
+
# column of closing prices to new DataFrame
|
|
252
|
+
for ticker in data_list:
|
|
253
|
+
chart_data[ticker] = tables['ticker_dict'][ticker]['Close']
|
|
254
|
+
|
|
255
|
+
# Rename columns from tickers to short names and forward fill
|
|
256
|
+
# any NaN cells
|
|
257
|
+
chart_data = chart_data.rename(
|
|
258
|
+
columns=params['ticker_short_name_dict'])
|
|
259
|
+
chart_data = chart_data.ffill()
|
|
260
|
+
|
|
261
|
+
return chart_data
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@classmethod
|
|
265
|
+
def create_data_list(
|
|
266
|
+
cls,
|
|
267
|
+
params: dict,
|
|
268
|
+
barometer: pd.DataFrame,
|
|
269
|
+
market_chart: bool,
|
|
270
|
+
num_charts: int | None) -> list:
|
|
271
|
+
"""
|
|
272
|
+
Create a list of the most / least trending markets.
|
|
273
|
+
|
|
274
|
+
Parameters
|
|
275
|
+
----------
|
|
276
|
+
params : Dict
|
|
277
|
+
mkts : Int
|
|
278
|
+
Number of markets to chart. The default is 5.
|
|
279
|
+
trend : Str
|
|
280
|
+
Flag to select most or least trending markets.
|
|
281
|
+
Select from: 'up' - strongly trending upwards,
|
|
282
|
+
'down - strongly trending downwards,
|
|
283
|
+
'neutral' - weak trend,
|
|
284
|
+
'strong' - up and down trends,
|
|
285
|
+
'all' - up down and weak trends
|
|
286
|
+
The default is 'strong' which displays both up-trending
|
|
287
|
+
and down-trending markets.
|
|
288
|
+
barometer : DataFrame
|
|
289
|
+
DataFrame showing trend strength for each ticker.
|
|
290
|
+
market_chart : Bool
|
|
291
|
+
Whether the data is used for the marketchart graph. The
|
|
292
|
+
default is False
|
|
293
|
+
num_charts : Int
|
|
294
|
+
The number of sub plots in the market chart. The default is 40.
|
|
295
|
+
|
|
296
|
+
Returns
|
|
297
|
+
-------
|
|
298
|
+
data_list : List
|
|
299
|
+
List of markets to be charted.
|
|
300
|
+
|
|
301
|
+
"""
|
|
302
|
+
trend = params['trend']
|
|
303
|
+
mkts = params['mkts']
|
|
304
|
+
|
|
305
|
+
# if trend flag is 'up', select tickers of most up trending
|
|
306
|
+
# markets
|
|
307
|
+
if trend == 'up':
|
|
308
|
+
data_list = cls._up_trend(
|
|
309
|
+
barometer=barometer, market_chart=market_chart,
|
|
310
|
+
num_charts=num_charts, mkts=mkts)
|
|
311
|
+
|
|
312
|
+
# if trend flag is 'down', select tickers of most down trending
|
|
313
|
+
# markets
|
|
314
|
+
elif trend == 'down':
|
|
315
|
+
data_list = cls._down_trend(
|
|
316
|
+
barometer=barometer, market_chart=market_chart,
|
|
317
|
+
num_charts=num_charts, mkts=mkts)
|
|
318
|
+
|
|
319
|
+
# if trend flag is 'neutral', select tickers of least trending
|
|
320
|
+
# markets
|
|
321
|
+
elif trend == 'neutral':
|
|
322
|
+
data_list = cls._neutral_trend(
|
|
323
|
+
barometer=barometer, market_chart=market_chart,
|
|
324
|
+
num_charts=num_charts, mkts=mkts)
|
|
325
|
+
|
|
326
|
+
# if trend flag is 'strong', select tickers of most down trending
|
|
327
|
+
# markets
|
|
328
|
+
elif trend == 'strong':
|
|
329
|
+
data_list = cls._strong_trend(
|
|
330
|
+
barometer=barometer, market_chart=market_chart,
|
|
331
|
+
num_charts=num_charts, mkts=mkts)
|
|
332
|
+
|
|
333
|
+
# Otherwise select all 3
|
|
334
|
+
else:
|
|
335
|
+
data_list = cls._mixed_trend(
|
|
336
|
+
barometer=barometer, market_chart=market_chart,
|
|
337
|
+
num_charts=num_charts, mkts=mkts)
|
|
338
|
+
|
|
339
|
+
return data_list
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@staticmethod
|
|
343
|
+
def _up_trend(
|
|
344
|
+
barometer: pd.DataFrame,
|
|
345
|
+
market_chart: bool,
|
|
346
|
+
num_charts: int | None,
|
|
347
|
+
mkts: int) -> list:
|
|
348
|
+
|
|
349
|
+
# Sort by Trend Strength
|
|
350
|
+
barometer = barometer.sort_values(
|
|
351
|
+
by=['Trend Strength'], ascending=False)
|
|
352
|
+
|
|
353
|
+
if market_chart:
|
|
354
|
+
# Select the specified number of highest values
|
|
355
|
+
data_list = list(barometer['Ticker'].iloc[:num_charts])
|
|
356
|
+
|
|
357
|
+
else:
|
|
358
|
+
# Select the highest values
|
|
359
|
+
data_list = list(barometer['Ticker'].iloc[:mkts])
|
|
360
|
+
|
|
361
|
+
return data_list
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
@staticmethod
|
|
365
|
+
def _down_trend(
|
|
366
|
+
barometer: pd.DataFrame,
|
|
367
|
+
market_chart: bool,
|
|
368
|
+
num_charts: int | None,
|
|
369
|
+
mkts: int) -> list:
|
|
370
|
+
|
|
371
|
+
# Sort by Trend Strength
|
|
372
|
+
barometer = barometer.sort_values(
|
|
373
|
+
by=['Trend Strength'], ascending=False)
|
|
374
|
+
|
|
375
|
+
if (market_chart and num_charts !=None) :
|
|
376
|
+
# Select the specified number of lowest values
|
|
377
|
+
data_list = list(barometer['Ticker'].iloc[-num_charts:])
|
|
378
|
+
|
|
379
|
+
else:
|
|
380
|
+
# Select the lowest values
|
|
381
|
+
data_list = list(barometer['Ticker'].iloc[-mkts:])
|
|
382
|
+
|
|
383
|
+
return data_list
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
@staticmethod
|
|
387
|
+
def _neutral_trend(
|
|
388
|
+
barometer: pd.DataFrame,
|
|
389
|
+
market_chart: bool,
|
|
390
|
+
num_charts: int | None,
|
|
391
|
+
mkts: int) -> list:
|
|
392
|
+
|
|
393
|
+
# Sort by Absolute Trend Strength
|
|
394
|
+
barometer = barometer.sort_values(
|
|
395
|
+
by=['Absolute Trend Strength'], ascending=False)
|
|
396
|
+
|
|
397
|
+
if (market_chart and num_charts !=None):
|
|
398
|
+
# Select the specified number of lowest values
|
|
399
|
+
data_list = list(barometer['Ticker'].iloc[-num_charts:])
|
|
400
|
+
|
|
401
|
+
else:
|
|
402
|
+
# Select the lowest values
|
|
403
|
+
data_list = list(barometer['Ticker'].iloc[-mkts:])
|
|
404
|
+
|
|
405
|
+
return data_list
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
@staticmethod
|
|
409
|
+
def _strong_trend(
|
|
410
|
+
barometer: pd.DataFrame,
|
|
411
|
+
market_chart: bool,
|
|
412
|
+
num_charts: int | None,
|
|
413
|
+
mkts: int) -> list:
|
|
414
|
+
|
|
415
|
+
# Sort by Trend Strength
|
|
416
|
+
barometer = barometer.sort_values(
|
|
417
|
+
by=['Trend Strength'], ascending=False)
|
|
418
|
+
|
|
419
|
+
if (market_chart and num_charts !=None):
|
|
420
|
+
# Select the specified number of highest values
|
|
421
|
+
top = list(barometer['Ticker'].iloc[:int(num_charts/2)])
|
|
422
|
+
|
|
423
|
+
# Select the lowest values
|
|
424
|
+
bottom = list(barometer['Ticker'].iloc[
|
|
425
|
+
-(num_charts-int(num_charts/2)):])
|
|
426
|
+
|
|
427
|
+
else:
|
|
428
|
+
# Select the highest values
|
|
429
|
+
top = list(barometer['Ticker'].iloc[:int(mkts/2)])
|
|
430
|
+
|
|
431
|
+
# Select the lowest values
|
|
432
|
+
bottom = list(barometer['Ticker'].iloc[
|
|
433
|
+
-(mkts-int(mkts/2)):])
|
|
434
|
+
|
|
435
|
+
# Combine this data
|
|
436
|
+
data_list = top + bottom
|
|
437
|
+
|
|
438
|
+
return data_list
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
@staticmethod
|
|
442
|
+
def _mixed_trend(
|
|
443
|
+
barometer: pd.DataFrame,
|
|
444
|
+
market_chart: bool,
|
|
445
|
+
num_charts: int | None,
|
|
446
|
+
mkts: int) -> list:
|
|
447
|
+
|
|
448
|
+
# Sort by Trend Strength
|
|
449
|
+
barometer = barometer.sort_values(
|
|
450
|
+
by=['Trend Strength'], ascending=False)
|
|
451
|
+
|
|
452
|
+
if (market_chart and num_charts !=None):
|
|
453
|
+
# Select 1/3 of the specified number of highest values
|
|
454
|
+
top = list(barometer['Ticker'].iloc[:int(num_charts/3)])
|
|
455
|
+
|
|
456
|
+
# Select 1/3 of the specified number of lowest values
|
|
457
|
+
bottom = list(barometer['Ticker'].iloc[-int(num_charts/3):])
|
|
458
|
+
|
|
459
|
+
# Sort by Absolute Trend Strength
|
|
460
|
+
barometer = barometer.sort_values(
|
|
461
|
+
by=['Absolute Trend Strength'], ascending=False)
|
|
462
|
+
|
|
463
|
+
# Select 1/3 of the specified number of lowest values
|
|
464
|
+
neutral = list(barometer['Ticker'].iloc[
|
|
465
|
+
-(num_charts-2*int(num_charts/3)):])
|
|
466
|
+
|
|
467
|
+
else:
|
|
468
|
+
# Select the highest values
|
|
469
|
+
top = list(barometer['Ticker'].iloc[:int(mkts/3)])
|
|
470
|
+
|
|
471
|
+
# Select the lowest values
|
|
472
|
+
bottom = list(barometer['Ticker'].iloc[-int(mkts/3):])
|
|
473
|
+
|
|
474
|
+
# Sort by Absolute Trend Strength
|
|
475
|
+
barometer = barometer.sort_values(
|
|
476
|
+
by=['Absolute Trend Strength'], ascending=False)
|
|
477
|
+
|
|
478
|
+
# Select the lowest values
|
|
479
|
+
neutral = list(barometer['Ticker'].iloc[
|
|
480
|
+
-(mkts-2*int(mkts/3)):])
|
|
481
|
+
|
|
482
|
+
# Combine this data
|
|
483
|
+
data_list = top + bottom + neutral
|
|
484
|
+
|
|
485
|
+
return data_list
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
@classmethod
|
|
489
|
+
def summary_config(
|
|
490
|
+
cls,
|
|
491
|
+
params: dict,
|
|
492
|
+
barometer: pd.DataFrame) -> tuple[dict, pd.DataFrame]:
|
|
493
|
+
"""
|
|
494
|
+
Configure inputs for Trend Summary plots
|
|
495
|
+
|
|
496
|
+
Parameters
|
|
497
|
+
----------
|
|
498
|
+
params : Dict
|
|
499
|
+
sector_level / returns_sector_level : Int, optional
|
|
500
|
+
The level of granularity of the assets.
|
|
501
|
+
For Commodities the choices are:
|
|
502
|
+
1:'Asset Class',
|
|
503
|
+
2:'Broad Sector',
|
|
504
|
+
3:'Mid Sector',
|
|
505
|
+
4:'Narrow Sector',
|
|
506
|
+
5:'Underlying'. The default is 2:'Broad Sector'.
|
|
507
|
+
For Equities the choices are:
|
|
508
|
+
1:'Sector',
|
|
509
|
+
2:'Industry Group',
|
|
510
|
+
3:'Industry',
|
|
511
|
+
4:'Sub-Industry',
|
|
512
|
+
5:'Security'
|
|
513
|
+
|
|
514
|
+
absolute : Bool, optional
|
|
515
|
+
Whether to show absolute trend strength (from 0 - 100%) or show
|
|
516
|
+
positive and negative trends seperately
|
|
517
|
+
|
|
518
|
+
data_types : Str or List
|
|
519
|
+
Data types to use. Choose from 'c': continuous futures,
|
|
520
|
+
'r':ratios, 's':spot cash commodities, 'i':indices, 'y':yields.
|
|
521
|
+
The default is ['c', 's']
|
|
522
|
+
barometer : DataFrame
|
|
523
|
+
DataFrame showing trend strength for each ticker.
|
|
524
|
+
|
|
525
|
+
Returns
|
|
526
|
+
-------
|
|
527
|
+
params : Dict
|
|
528
|
+
sector_name : Str
|
|
529
|
+
The sector level used to summarize the data.
|
|
530
|
+
marker_size : Int
|
|
531
|
+
The size of the markers in the strip plot.
|
|
532
|
+
trend_type : Str
|
|
533
|
+
Absolute or relavive trend strength.
|
|
534
|
+
chart_barometer : DataFrame
|
|
535
|
+
Data source used to produce charts.
|
|
536
|
+
|
|
537
|
+
"""
|
|
538
|
+
# Set sector names and marker size when using Norgate futures data
|
|
539
|
+
if params['asset_type'] == 'CTA':
|
|
540
|
+
params['sector_name'] = params[
|
|
541
|
+
'commodity_sector_levels'][params['sector_level']-1]
|
|
542
|
+
params['returns_sector_name'] = params[
|
|
543
|
+
'commodity_sector_levels'][params['returns_sector_level']-1]
|
|
544
|
+
params['marker_size'] = 10
|
|
545
|
+
|
|
546
|
+
# 'all' is used to select all of the Norgate data types
|
|
547
|
+
if params['data_types'] == 'all':
|
|
548
|
+
chart_barometer = barometer
|
|
549
|
+
|
|
550
|
+
# If the type is a string, remove all the other types
|
|
551
|
+
elif isinstance(params['data_types'], str):
|
|
552
|
+
chart_barometer = barometer
|
|
553
|
+
for tick in list(params['graph_ticker_types'].values()):
|
|
554
|
+
if tick[0] != params['data_types']:
|
|
555
|
+
chart_barometer.drop(
|
|
556
|
+
index=chart_barometer[
|
|
557
|
+
chart_barometer['Ticker'].str.contains(
|
|
558
|
+
tick)].index, inplace=True)
|
|
559
|
+
|
|
560
|
+
# If the result is a list, remove all the types not in the list
|
|
561
|
+
elif isinstance(params['data_types'], list):
|
|
562
|
+
chart_barometer = barometer
|
|
563
|
+
for tick in list(params['graph_ticker_types'].values()):
|
|
564
|
+
if tick[0] not in params['data_types']:
|
|
565
|
+
chart_barometer.drop(
|
|
566
|
+
index=chart_barometer[
|
|
567
|
+
chart_barometer['Ticker'].str.contains(
|
|
568
|
+
tick)].index, inplace=True)
|
|
569
|
+
|
|
570
|
+
# Print an error message if an incorrect type is supplied
|
|
571
|
+
else:
|
|
572
|
+
print('Enter a valid ticker type')
|
|
573
|
+
|
|
574
|
+
# Otherwise for Yahoo SPX data
|
|
575
|
+
else:
|
|
576
|
+
params['sector_name'] = params[
|
|
577
|
+
'equity_sector_levels'][params['sector_level']-1]
|
|
578
|
+
params['returns_sector_name'] = params[
|
|
579
|
+
'equity_sector_levels'][params['returns_sector_level']-1]
|
|
580
|
+
params['marker_size'] = 10
|
|
581
|
+
chart_barometer = barometer
|
|
582
|
+
|
|
583
|
+
# Set label for Absolute trend strength ranging from 0% to 100%
|
|
584
|
+
if params['absolute']:
|
|
585
|
+
params['trend_type'] = 'Absolute Trend Strength %'
|
|
586
|
+
params['axis_range'] = [-0.1,1]
|
|
587
|
+
|
|
588
|
+
# Or splitting uptrends and downtrends ranging from -100% to 100%
|
|
589
|
+
else:
|
|
590
|
+
params['trend_type'] = 'Trend Strength %'
|
|
591
|
+
params['axis_range'] = [-1,1]
|
|
592
|
+
|
|
593
|
+
trend_sector_group = chart_barometer[
|
|
594
|
+
[params['trend_type'], params['sector_name']]]
|
|
595
|
+
|
|
596
|
+
# Set the maximum height of the chart
|
|
597
|
+
params['plot_height'] = cls._set_height(
|
|
598
|
+
params=params, chart_barometer=chart_barometer,
|
|
599
|
+
trend_sector_group=trend_sector_group)
|
|
600
|
+
|
|
601
|
+
# Rank the sector split by average of the trend_type
|
|
602
|
+
sect_data = trend_sector_group.groupby([params['sector_name']]).mean()
|
|
603
|
+
params['sector_list'] = list(sect_data.sort_values(
|
|
604
|
+
params['trend_type'], ascending=False).index)
|
|
605
|
+
|
|
606
|
+
# Sort chart barometer by trend type
|
|
607
|
+
chart_barometer = chart_barometer.sort_values(
|
|
608
|
+
by=[params['trend_type']], ascending=True)
|
|
609
|
+
|
|
610
|
+
return params, chart_barometer
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
@staticmethod
|
|
614
|
+
def _set_height(
|
|
615
|
+
params: dict,
|
|
616
|
+
chart_barometer: pd.DataFrame,
|
|
617
|
+
trend_sector_group: pd.DataFrame) -> float:
|
|
618
|
+
|
|
619
|
+
max_bucket = chart_barometer[params['trend_type']].value_counts().max()
|
|
620
|
+
|
|
621
|
+
max_bucket_per_sector = trend_sector_group.groupby(
|
|
622
|
+
trend_sector_group.columns.tolist()).size().max()
|
|
623
|
+
|
|
624
|
+
num_sectors = len(chart_barometer[params['sector_name']].unique())
|
|
625
|
+
|
|
626
|
+
if params['summary_type'] == 'strip':
|
|
627
|
+
if num_sectors > 200:
|
|
628
|
+
plot_height = max_bucket_per_sector * num_sectors / 5
|
|
629
|
+
else:
|
|
630
|
+
plot_height = max_bucket_per_sector * num_sectors / 20
|
|
631
|
+
else:
|
|
632
|
+
if params['dodge']:
|
|
633
|
+
plot_height = max_bucket_per_sector * num_sectors / 8
|
|
634
|
+
else:
|
|
635
|
+
plot_height = max_bucket / 4
|
|
636
|
+
|
|
637
|
+
return plot_height
|