wnstnb commited on
Commit
614a841
·
1 Parent(s): af7c3c8

add more feats

Browse files
Files changed (5) hide show
  1. model_1h.py +23 -14
  2. model_30m.py +23 -17
  3. model_90m.py +23 -14
  4. model_day.py +18 -10
  5. troubleshoot_day_model.ipynb +380 -378
model_1h.py CHANGED
@@ -49,6 +49,27 @@ def walk_forward_validation(df, target_column, num_training_rows, num_periods):
49
  # Return the true and predicted values, and fitted model
50
  return df_results, model
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_training_rows, num_periods):
53
 
54
  # Create run the regression model to get its target
@@ -61,14 +82,7 @@ def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_t
61
  for_merge['RegrModelOut'] = for_merge['RegrModelOut'] > 0
62
  df = df.merge(for_merge, left_index=True, right_index=True)
63
  df = df.drop(columns=[target_column_regr])
64
- df = df[[
65
- 'CurrentGap','RegrModelOut',
66
- 'CurrentHigh30toClose',
67
- 'CurrentLow30toClose',
68
- 'CurrentClose30toClose',
69
- 'CurrentRange30',
70
- 'GapFill30',target_column_clf
71
- ]]
72
 
73
  df[target_column_clf] = df[target_column_clf].astype(bool)
74
  df['RegrModelOut'] = df['RegrModelOut'].astype(bool)
@@ -109,12 +123,7 @@ def seq_predict_proba(df, trained_reg_model, trained_clf_model):
109
  regr_pred = regr_pred > 0
110
  new_df = df.copy()
111
  new_df['RegrModelOut'] = regr_pred
112
- clf_pred_proba = trained_clf_model.predict_proba(new_df[['CurrentGap','RegrModelOut',
113
- 'CurrentHigh30toClose',
114
- 'CurrentLow30toClose',
115
- 'CurrentClose30toClose',
116
- 'CurrentRange30',
117
- 'GapFill30']])[:,-1]
118
  return clf_pred_proba
119
 
120
  def get_data():
 
49
  # Return the true and predicted values, and fitted model
50
  return df_results, model
51
 
52
+ model_cols = [
53
+ 'BigNewsDay',
54
+ 'Quarter',
55
+ 'Perf5Day',
56
+ 'Perf5Day_n1',
57
+ 'DaysGreen',
58
+ 'DaysRed',
59
+ 'CurrentHigh30toClose',
60
+ 'CurrentLow30toClose',
61
+ 'CurrentClose30toClose',
62
+ 'CurrentRange30',
63
+ 'GapFill30',
64
+ 'CurrentGap',
65
+ 'RangePct',
66
+ 'RangePct_n1',
67
+ 'RangePct_n2',
68
+ 'OHLC4_VIX',
69
+ 'OHLC4_VIX_n1',
70
+ 'OHLC4_VIX_n2'
71
+ ]
72
+
73
  def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_training_rows, num_periods):
74
 
75
  # Create run the regression model to get its target
 
82
  for_merge['RegrModelOut'] = for_merge['RegrModelOut'] > 0
83
  df = df.merge(for_merge, left_index=True, right_index=True)
84
  df = df.drop(columns=[target_column_regr])
85
+ df = df[model_cols + ['RegrModelOut', target_column_clf]]
 
 
 
 
 
 
 
86
 
87
  df[target_column_clf] = df[target_column_clf].astype(bool)
88
  df['RegrModelOut'] = df['RegrModelOut'].astype(bool)
 
123
  regr_pred = regr_pred > 0
124
  new_df = df.copy()
125
  new_df['RegrModelOut'] = regr_pred
126
+ clf_pred_proba = trained_clf_model.predict_proba(new_df[model_cols + ['RegrModelOut']])[:,-1]
 
 
 
 
 
127
  return clf_pred_proba
128
 
129
  def get_data():
model_30m.py CHANGED
@@ -50,6 +50,27 @@ def walk_forward_validation(df, target_column, num_training_rows, num_periods):
50
  # Return the true and predicted values, and fitted model
51
  return df_results, model
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_training_rows, num_periods):
54
 
55
  # Create run the regression model to get its target
@@ -62,13 +83,7 @@ def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_t
62
  for_merge['RegrModelOut'] = for_merge['RegrModelOut'] > 0
63
  df = df.merge(for_merge, left_index=True, right_index=True)
64
  df = df.drop(columns=[target_column_regr])
65
- df = df[[
66
- 'CurrentGap','RegrModelOut','CurrentHigh30toClose',
67
- 'CurrentLow30toClose',
68
- 'CurrentClose30toClose',
69
- 'CurrentRange30',
70
- 'GapFill30', target_column_clf
71
- ]]
72
 
73
  df[target_column_clf] = df[target_column_clf].astype(bool)
74
  df['RegrModelOut'] = df['RegrModelOut'].astype(bool)
@@ -107,11 +122,7 @@ def seq_predict_proba(df, trained_reg_model, trained_clf_model):
107
  regr_pred = regr_pred > 0
108
  new_df = df.copy()
109
  new_df['RegrModelOut'] = regr_pred
110
- clf_pred_proba = trained_clf_model.predict_proba(new_df[['CurrentGap','RegrModelOut','CurrentHigh30toClose',
111
- 'CurrentLow30toClose',
112
- 'CurrentClose30toClose',
113
- 'CurrentRange30',
114
- 'GapFill30']])[:,-1]
115
  return clf_pred_proba
116
 
117
  def get_data():
@@ -371,11 +382,6 @@ def get_data():
371
  'CurrentClose30toClose',
372
  'CurrentRange30',
373
  'GapFill30',
374
- # 'OHLC4_Trend',
375
- # 'OHLC4_Trend_n1',
376
- # 'OHLC4_Trend_n2',
377
- # 'VIX5Day',
378
- # 'VIX5Day_n1',
379
  'CurrentGap',
380
  'RangePct',
381
  'RangePct_n1',
 
50
  # Return the true and predicted values, and fitted model
51
  return df_results, model
52
 
53
+ model_cols = [
54
+ 'BigNewsDay',
55
+ 'Quarter',
56
+ 'Perf5Day',
57
+ 'Perf5Day_n1',
58
+ 'DaysGreen',
59
+ 'DaysRed',
60
+ 'CurrentHigh30toClose',
61
+ 'CurrentLow30toClose',
62
+ 'CurrentClose30toClose',
63
+ 'CurrentRange30',
64
+ 'GapFill30',
65
+ 'CurrentGap',
66
+ 'RangePct',
67
+ 'RangePct_n1',
68
+ 'RangePct_n2',
69
+ 'OHLC4_VIX',
70
+ 'OHLC4_VIX_n1',
71
+ 'OHLC4_VIX_n2'
72
+ ]
73
+
74
  def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_training_rows, num_periods):
75
 
76
  # Create run the regression model to get its target
 
83
  for_merge['RegrModelOut'] = for_merge['RegrModelOut'] > 0
84
  df = df.merge(for_merge, left_index=True, right_index=True)
85
  df = df.drop(columns=[target_column_regr])
86
+ df = df[model_cols + ['RegrModelOut', target_column_clf]]
 
 
 
 
 
 
87
 
88
  df[target_column_clf] = df[target_column_clf].astype(bool)
89
  df['RegrModelOut'] = df['RegrModelOut'].astype(bool)
 
122
  regr_pred = regr_pred > 0
123
  new_df = df.copy()
124
  new_df['RegrModelOut'] = regr_pred
125
+ clf_pred_proba = trained_clf_model.predict_proba(new_df[model_cols + ['RegrModelOut']])[:,-1]
 
 
 
 
126
  return clf_pred_proba
127
 
128
  def get_data():
 
382
  'CurrentClose30toClose',
383
  'CurrentRange30',
384
  'GapFill30',
 
 
 
 
 
385
  'CurrentGap',
386
  'RangePct',
387
  'RangePct_n1',
model_90m.py CHANGED
@@ -49,6 +49,27 @@ def walk_forward_validation(df, target_column, num_training_rows, num_periods):
49
  # Return the true and predicted values, and fitted model
50
  return df_results, model
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_training_rows, num_periods):
53
 
54
  # Create run the regression model to get its target
@@ -61,14 +82,7 @@ def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_t
61
  for_merge['RegrModelOut'] = for_merge['RegrModelOut'] > 0
62
  df = df.merge(for_merge, left_index=True, right_index=True)
63
  df = df.drop(columns=[target_column_regr])
64
- df = df[[
65
- 'CurrentGap','RegrModelOut',
66
- 'CurrentHigh30toClose',
67
- 'CurrentLow30toClose',
68
- 'CurrentClose30toClose',
69
- 'CurrentRange30',
70
- 'GapFill30',target_column_clf
71
- ]]
72
 
73
  df[target_column_clf] = df[target_column_clf].astype(bool)
74
  df['RegrModelOut'] = df['RegrModelOut'].astype(bool)
@@ -109,12 +123,7 @@ def seq_predict_proba(df, trained_reg_model, trained_clf_model):
109
  regr_pred = regr_pred > 0
110
  new_df = df.copy()
111
  new_df['RegrModelOut'] = regr_pred
112
- clf_pred_proba = trained_clf_model.predict_proba(new_df[['CurrentGap','RegrModelOut',
113
- 'CurrentHigh30toClose',
114
- 'CurrentLow30toClose',
115
- 'CurrentClose30toClose',
116
- 'CurrentRange30',
117
- 'GapFill30']])[:,-1]
118
  return clf_pred_proba
119
 
120
  def get_data():
 
49
  # Return the true and predicted values, and fitted model
50
  return df_results, model
51
 
52
+ model_cols = [
53
+ 'BigNewsDay',
54
+ 'Quarter',
55
+ 'Perf5Day',
56
+ 'Perf5Day_n1',
57
+ 'DaysGreen',
58
+ 'DaysRed',
59
+ 'CurrentHigh30toClose',
60
+ 'CurrentLow30toClose',
61
+ 'CurrentClose30toClose',
62
+ 'CurrentRange30',
63
+ 'GapFill30',
64
+ 'CurrentGap',
65
+ 'RangePct',
66
+ 'RangePct_n1',
67
+ 'RangePct_n2',
68
+ 'OHLC4_VIX',
69
+ 'OHLC4_VIX_n1',
70
+ 'OHLC4_VIX_n2'
71
+ ]
72
+
73
  def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_training_rows, num_periods):
74
 
75
  # Create run the regression model to get its target
 
82
  for_merge['RegrModelOut'] = for_merge['RegrModelOut'] > 0
83
  df = df.merge(for_merge, left_index=True, right_index=True)
84
  df = df.drop(columns=[target_column_regr])
85
+ df = df[model_cols + ['RegrModelOut', target_column_clf]]
 
 
 
 
 
 
 
86
 
87
  df[target_column_clf] = df[target_column_clf].astype(bool)
88
  df['RegrModelOut'] = df['RegrModelOut'].astype(bool)
 
123
  regr_pred = regr_pred > 0
124
  new_df = df.copy()
125
  new_df['RegrModelOut'] = regr_pred
126
+ clf_pred_proba = trained_clf_model.predict_proba(new_df[model_cols + ['RegrModelOut']])[:,-1]
 
 
 
 
 
127
  return clf_pred_proba
128
 
129
  def get_data():
model_day.py CHANGED
@@ -17,7 +17,6 @@ import datetime
17
  from pandas.tseries.offsets import BDay
18
  import lightgbm as lgb
19
 
20
-
21
  def walk_forward_validation(df, target_column, num_training_rows, num_periods):
22
 
23
  # Create an XGBRegressor model
@@ -49,6 +48,22 @@ def walk_forward_validation(df, target_column, num_training_rows, num_periods):
49
  # Return the true and predicted values, and fitted model
50
  return df_results, model
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_training_rows, num_periods):
53
 
54
  # Create run the regression model to get its target
@@ -61,9 +76,7 @@ def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_t
61
  for_merge['RegrModelOut'] = for_merge['RegrModelOut'] > 0
62
  df = df.merge(for_merge, left_index=True, right_index=True)
63
  df = df.drop(columns=[target_column_regr])
64
- df = df[[
65
- 'CurrentGap','RegrModelOut',target_column_clf
66
- ]]
67
 
68
  df[target_column_clf] = df[target_column_clf].astype(bool)
69
  df['RegrModelOut'] = df['RegrModelOut'].astype(bool)
@@ -104,7 +117,7 @@ def seq_predict_proba(df, trained_reg_model, trained_clf_model):
104
  regr_pred = regr_pred > 0
105
  new_df = df.copy()
106
  new_df['RegrModelOut'] = regr_pred
107
- clf_pred_proba = trained_clf_model.predict_proba(new_df[['CurrentGap','RegrModelOut']])[:,-1]
108
  return clf_pred_proba
109
 
110
  def get_data():
@@ -303,11 +316,6 @@ def get_data():
303
  'Perf5Day_n1',
304
  'DaysGreen',
305
  'DaysRed',
306
- # 'OHLC4_Trend',
307
- # 'OHLC4_Trend_n1',
308
- # 'OHLC4_Trend_n2',
309
- # 'VIX5Day',
310
- # 'VIX5Day_n1',
311
  'CurrentGap',
312
  'RangePct',
313
  'RangePct_n1',
 
17
  from pandas.tseries.offsets import BDay
18
  import lightgbm as lgb
19
 
 
20
  def walk_forward_validation(df, target_column, num_training_rows, num_periods):
21
 
22
  # Create an XGBRegressor model
 
48
  # Return the true and predicted values, and fitted model
49
  return df_results, model
50
 
51
+ model_cols = [
52
+ 'BigNewsDay',
53
+ 'Quarter',
54
+ 'Perf5Day',
55
+ 'Perf5Day_n1',
56
+ 'DaysGreen',
57
+ 'DaysRed',
58
+ 'CurrentGap',
59
+ 'RangePct',
60
+ 'RangePct_n1',
61
+ 'RangePct_n2',
62
+ 'OHLC4_VIX',
63
+ 'OHLC4_VIX_n1',
64
+ 'OHLC4_VIX_n2'
65
+ ]
66
+
67
  def walk_forward_validation_seq(df, target_column_clf, target_column_regr, num_training_rows, num_periods):
68
 
69
  # Create run the regression model to get its target
 
76
  for_merge['RegrModelOut'] = for_merge['RegrModelOut'] > 0
77
  df = df.merge(for_merge, left_index=True, right_index=True)
78
  df = df.drop(columns=[target_column_regr])
79
+ df = df[model_cols + ['RegrModelOut', target_column_clf]]
 
 
80
 
81
  df[target_column_clf] = df[target_column_clf].astype(bool)
82
  df['RegrModelOut'] = df['RegrModelOut'].astype(bool)
 
117
  regr_pred = regr_pred > 0
118
  new_df = df.copy()
119
  new_df['RegrModelOut'] = regr_pred
120
+ clf_pred_proba = trained_clf_model.predict_proba(new_df[model_cols + ['RegrModelOut']])[:,-1]
121
  return clf_pred_proba
122
 
123
  def get_data():
 
316
  'Perf5Day_n1',
317
  'DaysGreen',
318
  'DaysRed',
 
 
 
 
 
319
  'CurrentGap',
320
  'RangePct',
321
  'RangePct_n1',
troubleshoot_day_model.ipynb CHANGED
@@ -4,20 +4,11 @@
4
  "cell_type": "code",
5
  "execution_count": 1,
6
  "metadata": {},
7
- "outputs": [
8
- {
9
- "name": "stderr",
10
- "output_type": "stream",
11
- "text": [
12
- "Found cached dataset text (C:/Users/WINSTON-ITX/.cache/huggingface/datasets/boomsss___text/boomsss--SPX_full_30min-37ae67efd8a1cc91/0.0.0/cb1e9bd71a82ad27976be3b12b407850fe2837d80c22c5e03a28949843a8ace2)\n"
13
- ]
14
- }
15
- ],
16
  "source": [
17
  "import pandas as pd\n",
18
  "import numpy as np\n",
19
- "from model_day import get_data, walk_forward_validation_seq\n",
20
- "import xgboost as xgb"
21
  ]
22
  },
23
  {
@@ -29,10 +20,11 @@
29
  "name": "stderr",
30
  "output_type": "stream",
31
  "text": [
32
- "getting econ tickers: 100%|██████████| 3/3 [00:01<00:00, 2.62it/s]\n",
33
- "Getting release dates: 100%|██████████| 8/8 [00:02<00:00, 3.85it/s]\n",
34
- "Making indicators: 100%|██████████| 8/8 [00:00<00:00, 2664.95it/s]\n",
35
- "Merging econ data: 100%|██████████| 8/8 [00:00<00:00, 999.15it/s]\n"
 
36
  ]
37
  }
38
  ],
@@ -54,21 +46,21 @@
54
  },
55
  {
56
  "cell_type": "code",
57
- "execution_count": 4,
58
  "metadata": {},
59
  "outputs": [
60
  {
61
  "name": "stderr",
62
  "output_type": "stream",
63
  "text": [
64
- "LR Model: 100%|██████████| 1178/1178 [00:03<00:00, 385.55it/s]\n",
65
- "d:\\Projects\\gamedayspx\\model_day.py:63: SettingWithCopyWarning: \n",
66
  "A value is trying to be set on a copy of a slice from a DataFrame.\n",
67
  "Try using .loc[row_indexer,col_indexer] = value instead\n",
68
  "\n",
69
  "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
70
  " for_merge['RegrModelOut'] = for_merge['RegrModelOut'] > 0\n",
71
- "CLF Model: 100%|██████████| 1078/1078 [00:09<00:00, 119.55it/s]\n"
72
  ]
73
  }
74
  ],
@@ -78,56 +70,40 @@
78
  },
79
  {
80
  "cell_type": "code",
81
- "execution_count": 5,
82
- "metadata": {},
83
- "outputs": [
84
- {
85
- "data": {
86
- "text/plain": [
87
- "<AxesSubplot:title={'center':'Feature importance'}, xlabel='F score', ylabel='Features'>"
88
- ]
89
- },
90
- "execution_count": 5,
91
- "metadata": {},
92
- "output_type": "execute_result"
93
- },
94
- {
95
- "data": {
96
- "image/png": "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T58+9OvXjwEDBvDkk08C8MYbbzBw4EB69uxJnz59ahyryllnnUWbNm2ql88555zqert160a7du3WWdcjjzxC//796devH/vuuy9vvPEGALfeeitbb7119fHGjBlTvc9NN91Ez5496d69O2eddRYRNb/BZNiwYfTq1avO18AsdcnNSZH0JeA6YA9gGfAucHZEzG6k85cBn0TE0wVt3wEuAJoClcDzwHkRsawxajLbmLRs2ZKpU6fSpk0bKioq2HfffRk6dCh777139Tb/+Mc/uOKKK3jqqado3749CxcuBOD999/n8ssvZ9q0aUhi9913Z9iwYbRv354ZM2ZU77/77rtz9NFHA3Deeedx4oknMmLECKZOncrFF1/M7bffzgMPPMD06dOZMWMGq1atoqysjKFDh9KmTRtGjBjBI488Qrdu3Rg5ciTjxo3j1FNPZfDgwQwbNgxJzJo1i2OOOYbXXnuNli1bctttt9G1a1fefvttdt99d4YMGVIdPKZNm8bSpUtrPA/XXntt9ePf//73vPjiiwD11tW2bVvOOOMM7rvvPrp3784f/vAHfvnLX3LrrbcCcOyxxzJ69Oga53j66ad5+eWXmTVrFgD77rsvjz32GGVlZQBMmjSpRnAy29gk1ZMiScA9QHlE7BIRuwMXA52K3L/p2paLVAZ8reAYBwPnAEMjoifQH3i62JrMNjWSqt8YKyoqqKioIPtP+z9uueUWzjzzTNq3bw/ANttsA8Dzzz/PgQceSIcOHWjfvj0HHnggDz30UI19Z8+ezcKFC9lvv/0AePXVV9l///0B+MY3vsF9991X3T5o0CCaNWvG5ptvTp8+fXjooYdYsmQJLVq0oFu3bgAceOCBTJw4EYA2bdpU17py5crqxzvssANdu3YFYLvttmObbbZh0aJFAKxevZrzzz+f3/72t/U+J+PHj+f4449fa11Vz93772dfkbZ8+XK22267dT7Xn3zyCZ988gmrVq2ioqKCTp2y/zWtWLGCa665hksuuWStxzBLWVIhBfgGUBERN1U1RMRMoKmk+6vaJI2WdFL+eK6kKyVNB75Vx/JBkp6RNF3SXyS1Kdjv8rz9JUm7SdoJOB04R9IMSfsBPyPrNVmQ17M6IsZGxOv5cUZKel7Sy5JuzoMWksolXZ8f52VJezb802eWhtWrV9OvXz+22WYbDjzwQPbaa68a62fPns3s2bPZZ5992HvvvavfpBcvXswOO+xQvV3nzp1ZsGBBjX0nTJjAscceWx0g+vbty6RJkwC45557+OCDD1iyZAl9+/bloYce4sMPP2Tx4sU8+uijzJs3j44dO1JZWcm0adMAuPvuu5k3b1718e+55x522203Dj30UMaOHfupa3vuuef45JNP2GWXXQAYPXo0w4YNY9ttt63zuXjrrbeYM2dOdZCqry6AMWPGcMghh9C5c2duv/12LrroourjTJw4kT59+jB8+PDq7QcOHMhXv/pVtt12W7bddluGDBlC9+7dAbj00ks599xzad26df0vlFniUhvu6QW88Dn2WxIR/QEk/aZqWVJHYBJwQESslHQh8BPg5/l+i/PtfkAWRE6TdBOwIiJ+lx+vJzB9LeceHRE/z7e9HTgM+J98XeuI6CdpEDA2v74aJH0P+B5Ax45bM7J35ee4/IbXqVV2S21qUq0LGra28vLyz73vihUr1mv/Yl133XWsWLGCSy+9lN12242dd965et27777LkiVLuPzyy1m0aBEnnngiY8eOZdWqVcyZM6e6vjlz5tCyZcsa9Y4dO5aLL764uu3oo4/mhhtuYPTo0fTp04eOHTvyzDPP0KZNG7p3706fPn1o164dXbp0Yc6cOTz22GNccMEFnHLKKVRUVDBgwAA++uij6uO1b9+em266iZkzZ/LDH/6Qq6++uvo5W7JkCeeccw4XXXQRjz/+OIsXL2bMmDFcd911lJeXs3r16k89t+PHj2fgwIE88cQTALRo0aLOusrLyxk5ciS/+MUv6NGjBxMmTOD444/n/PPPp3379owbN44WLVowefJkjjjiCK655hoWLFjAm2++yfjx44Fs6KtTp060bt2a5557jiOOOIJnn32WlStXNsprXqixfs/siy21kPJ51Z7FVrW8N9ADeCr/q6sF8EzBdpPyf18Ajl7XSST1Bm4HtgB+GhF3At+QdAHQGugAvMJ/Qsp4gIh4XFJbSe1qz2OJiJuBmwF27LJrXP1Smi/Jub0rSbG2VOuChq1t7rfLPve+5eXl1XMWGsP06dNZsmQJJ598cnVb37592WuvvTjggAOArAehU6dObL/99ixcuLC6vvHjxzNo0KDq5ZkzZ9KiRQu+//3v1zjH8OHDgeyNcbfdduOwww4DqHGdJ5xwAocccghlZWWUlZVx5pln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",
97
- "text/plain": [
98
- "<Figure size 432x288 with 1 Axes>"
99
- ]
100
- },
101
- "metadata": {
102
- "needs_background": "light"
103
- },
104
- "output_type": "display_data"
105
- }
106
- ],
107
- "source": [
108
- "xgb.plot_importance(model2, importance_type='gain')"
109
- ]
110
- },
111
- {
112
- "cell_type": "code",
113
- "execution_count": 6,
114
  "metadata": {},
115
  "outputs": [],
116
  "source": [
117
  "from sklearn.metrics import roc_auc_score, precision_score, recall_score\n",
118
- "\n",
119
  "# st.subheader('New Prediction')\n",
 
120
  "\n",
121
- "# df_probas = res1.groupby(pd.qcut(res1['Predicted'],5)).agg({'True':[np.mean,len,np.sum]})\n",
122
- "df_probas = res1.groupby(pd.cut(res1['Predicted'],[-np.inf, 0.2, 0.4, 0.6, 0.8, np.inf])).agg({'True':[np.mean,len,np.sum]})\n",
123
  "df_probas.columns = ['PctGreen','NumObs','NumGreen']\n",
124
  "\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  "roc_auc_score_all = roc_auc_score(res1['True'].astype(int), res1['Predicted'].values)\n",
126
  "precision_score_all = precision_score(res1['True'].astype(int), res1['Predicted'] > 0.5)\n",
127
  "recall_score_all = recall_score(res1['True'].astype(int), res1['Predicted'] > 0.5)\n",
128
  "len_all = len(res1)\n",
129
  "\n",
130
- "res2_filtered = res1.loc[(res1['Predicted'] > 0.625) | (res1['Predicted'] <= 0.375)]\n",
131
  "\n",
132
  "roc_auc_score_hi = roc_auc_score(res2_filtered['True'].astype(int), res2_filtered['Predicted'].values)\n",
133
  "precision_score_hi = precision_score(res2_filtered['True'].astype(int), res2_filtered['Predicted'] > 0.5)\n",
@@ -154,49 +130,33 @@
154
  ").round(2)\n",
155
  "\n",
156
  "def get_acc(t, p):\n",
157
- " if t == False and p <= 0.375:\n",
158
- " return '✅'\n",
159
- " elif t == True and p > 0.625:\n",
160
- " return '✅'\n",
161
- " elif t == False and p > 0.625:\n",
162
- " return '❌'\n",
163
- " elif t == True and p <= 0.375:\n",
164
  " return '❌'\n",
165
  " else:\n",
166
- " return '🟨'\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  "\n",
168
  "perf_daily = res1.copy()\n",
169
- "perf_daily['Accuracy'] = [get_acc(t, p) for t, p in zip(perf_daily['True'], perf_daily['Predicted'])]"
170
- ]
171
- },
172
- {
173
- "cell_type": "code",
174
- "execution_count": 7,
175
- "metadata": {},
176
- "outputs": [],
177
- "source": [
178
- "perf_daily1 = perf_daily.merge(data['ClosePct'], left_index=True, right_index=True)"
179
- ]
180
- },
181
- {
182
- "cell_type": "code",
183
- "execution_count": 8,
184
- "metadata": {},
185
- "outputs": [],
186
- "source": [
187
- "res2 = res1.merge(data[['ClosePct','HighPct','LowPct']], left_index=True, right_index=True)"
188
- ]
189
- },
190
- {
191
- "cell_type": "code",
192
- "execution_count": 9,
193
- "metadata": {},
194
- "outputs": [],
195
- "source": [
196
- "int_labels = ['(-∞, .20]', '(.20, .40]', '(.40, .60]', '(.60, .80]', '(.80, ∞]']\n",
197
- "# df_probas = res1.groupby(pd.qcut(res1['Predicted'],5)).agg({'True':[np.mean,len,np.sum]})\n",
198
- "df_probas = res2.groupby(pd.cut(res2['Predicted'], bins = [-np.inf, 0.2, 0.4, 0.6, 0.8, np.inf], labels = int_labels)).agg({'True':[np.mean,len,np.sum],'ClosePct':[np.mean], 'HighPct':[np.mean], 'LowPct':[np.mean]})\n",
199
- "df_probas.columns = ['PctGreen','NumObs','NumGreen','AvgPerf','AvgHigh','AvgLow']"
200
  ]
201
  },
202
  {
@@ -228,78 +188,71 @@
228
  " <th>PctGreen</th>\n",
229
  " <th>NumObs</th>\n",
230
  " <th>NumGreen</th>\n",
231
- " <th>AvgPerf</th>\n",
232
- " <th>AvgHigh</th>\n",
233
- " <th>AvgLow</th>\n",
234
  " </tr>\n",
235
  " <tr>\n",
236
  " <th>Predicted</th>\n",
237
  " <th></th>\n",
238
  " <th></th>\n",
239
  " <th></th>\n",
240
- " <th></th>\n",
241
- " <th></th>\n",
242
- " <th></th>\n",
243
  " </tr>\n",
244
  " </thead>\n",
245
  " <tbody>\n",
246
  " <tr>\n",
247
- " <th>(-∞, .20]</th>\n",
248
- " <td>0.214286</td>\n",
249
- " <td>112</td>\n",
250
  " <td>24</td>\n",
251
- " <td>-0.012956</td>\n",
252
- " <td>0.009253</td>\n",
253
- " <td>-0.007881</td>\n",
254
  " </tr>\n",
255
  " <tr>\n",
256
- " <th>(.20, .40]</th>\n",
257
- " <td>0.322709</td>\n",
258
- " <td>251</td>\n",
259
- " <td>81</td>\n",
260
- " <td>-0.004048</td>\n",
261
- " <td>0.006433</td>\n",
262
- " <td>-0.005791</td>\n",
 
 
 
 
 
 
 
 
 
263
  " </tr>\n",
264
  " <tr>\n",
265
- " <th>(.40, .60]</th>\n",
266
- " <td>0.504630</td>\n",
267
- " <td>216</td>\n",
268
  " <td>109</td>\n",
269
- " <td>-0.000173</td>\n",
270
- " <td>0.006079</td>\n",
271
- " <td>-0.006083</td>\n",
272
  " </tr>\n",
273
  " <tr>\n",
274
- " <th>(.60, .80]</th>\n",
275
- " <td>0.645022</td>\n",
276
- " <td>231</td>\n",
277
- " <td>149</td>\n",
278
- " <td>0.002680</td>\n",
279
- " <td>0.006207</td>\n",
280
- " <td>-0.005687</td>\n",
281
  " </tr>\n",
282
  " <tr>\n",
283
- " <th>(.80, ]</th>\n",
284
- " <td>0.791045</td>\n",
285
- " <td>268</td>\n",
286
- " <td>212</td>\n",
287
- " <td>0.009038</td>\n",
288
- " <td>0.006807</td>\n",
289
- " <td>-0.007949</td>\n",
290
  " </tr>\n",
291
  " </tbody>\n",
292
  "</table>\n",
293
  "</div>"
294
  ],
295
  "text/plain": [
296
- " PctGreen NumObs NumGreen AvgPerf AvgHigh AvgLow\n",
297
- "Predicted \n",
298
- "(-∞, .20] 0.214286 112 24 -0.012956 0.009253 -0.007881\n",
299
- "(.20, .40] 0.322709 251 81 -0.004048 0.006433 -0.005791\n",
300
- "(.40, .60] 0.504630 216 109 -0.000173 0.006079 -0.006083\n",
301
- "(.60, .80] 0.645022 231 149 0.002680 0.006207 -0.005687\n",
302
- "(.80, ] 0.791045 268 212 0.009038 0.006807 -0.007949"
 
 
303
  ]
304
  },
305
  "execution_count": 10,
@@ -313,31 +266,286 @@
313
  },
314
  {
315
  "cell_type": "code",
316
- "execution_count": 11,
317
- "metadata": {},
318
- "outputs": [],
319
- "source": [
320
- "res2['Quantile'] = pd.cut(res2['Predicted'], bins = [-np.inf, 0.2, 0.4, 0.6, 0.8, np.inf], labels = int_labels)"
321
- ]
322
- },
323
- {
324
- "cell_type": "code",
325
- "execution_count": 12,
326
  "metadata": {},
327
  "outputs": [
328
  {
329
  "data": {
330
- "image/png": "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",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  "text/plain": [
332
- "<Figure size 1080x576 with 6 Axes>"
 
 
 
 
333
  ]
334
  },
335
- "metadata": {
336
- "needs_background": "light"
337
- },
338
- "output_type": "display_data"
339
  }
340
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  "source": [
342
  "import matplotlib.pyplot as plt\n",
343
  "\n",
@@ -369,7 +577,7 @@
369
  },
370
  {
371
  "cell_type": "code",
372
- "execution_count": 39,
373
  "metadata": {},
374
  "outputs": [],
375
  "source": [
@@ -401,169 +609,18 @@
401
  },
402
  {
403
  "cell_type": "code",
404
- "execution_count": 33,
405
  "metadata": {},
406
- "outputs": [
407
- {
408
- "data": {
409
- "text/html": [
410
- "<div>\n",
411
- "<style scoped>\n",
412
- " .dataframe tbody tr th:only-of-type {\n",
413
- " vertical-align: middle;\n",
414
- " }\n",
415
- "\n",
416
- " .dataframe tbody tr th {\n",
417
- " vertical-align: top;\n",
418
- " }\n",
419
- "\n",
420
- " .dataframe thead th {\n",
421
- " text-align: right;\n",
422
- " }\n",
423
- "</style>\n",
424
- "<table border=\"1\" class=\"dataframe\">\n",
425
- " <thead>\n",
426
- " <tr style=\"text-align: right;\">\n",
427
- " <th></th>\n",
428
- " <th>VIX_EM</th>\n",
429
- " <th>VIX_EM_15</th>\n",
430
- " <th>VIX_EM_15_High</th>\n",
431
- " <th>Close</th>\n",
432
- " </tr>\n",
433
- " <tr>\n",
434
- " <th>index</th>\n",
435
- " <th></th>\n",
436
- " <th></th>\n",
437
- " <th></th>\n",
438
- " <th></th>\n",
439
- " </tr>\n",
440
- " </thead>\n",
441
- " <tbody>\n",
442
- " <tr>\n",
443
- " <th>2018-07-02</th>\n",
444
- " <td>NaN</td>\n",
445
- " <td>NaN</td>\n",
446
- " <td>NaN</td>\n",
447
- " <td>2726.709961</td>\n",
448
- " </tr>\n",
449
- " <tr>\n",
450
- " <th>2018-07-03</th>\n",
451
- " <td>26.795587</td>\n",
452
- " <td>40.193381</td>\n",
453
- " <td>2766.903342</td>\n",
454
- " <td>2713.219971</td>\n",
455
- " </tr>\n",
456
- " <tr>\n",
457
- " <th>2018-07-05</th>\n",
458
- " <td>27.585969</td>\n",
459
- " <td>41.378954</td>\n",
460
- " <td>2754.598925</td>\n",
461
- " <td>2736.610107</td>\n",
462
- " </tr>\n",
463
- " <tr>\n",
464
- " <th>2018-07-06</th>\n",
465
- " <td>25.806818</td>\n",
466
- " <td>38.710227</td>\n",
467
- " <td>2775.320335</td>\n",
468
- " <td>2759.820068</td>\n",
469
- " </tr>\n",
470
- " <tr>\n",
471
- " <th>2018-07-09</th>\n",
472
- " <td>23.244055</td>\n",
473
- " <td>34.866083</td>\n",
474
- " <td>2794.686151</td>\n",
475
- " <td>2784.169922</td>\n",
476
- " </tr>\n",
477
- " <tr>\n",
478
- " <th>...</th>\n",
479
- " <td>...</td>\n",
480
- " <td>...</td>\n",
481
- " <td>...</td>\n",
482
- " <td>...</td>\n",
483
- " </tr>\n",
484
- " <tr>\n",
485
- " <th>2023-07-28</th>\n",
486
- " <td>41.188099</td>\n",
487
- " <td>61.782148</td>\n",
488
- " <td>4599.192304</td>\n",
489
- " <td>4582.229980</td>\n",
490
- " </tr>\n",
491
- " <tr>\n",
492
- " <th>2023-07-31</th>\n",
493
- " <td>38.477492</td>\n",
494
- " <td>57.716238</td>\n",
495
- " <td>4639.946219</td>\n",
496
- " <td>4588.959961</td>\n",
497
- " </tr>\n",
498
- " <tr>\n",
499
- " <th>2023-08-01</th>\n",
500
- " <td>39.401237</td>\n",
501
- " <td>59.101856</td>\n",
502
- " <td>4648.061817</td>\n",
503
- " <td>4576.729980</td>\n",
504
- " </tr>\n",
505
- " <tr>\n",
506
- " <th>2023-08-02</th>\n",
507
- " <td>40.161151</td>\n",
508
- " <td>60.241726</td>\n",
509
- " <td>4636.971706</td>\n",
510
- " <td>4513.390137</td>\n",
511
- " </tr>\n",
512
- " <tr>\n",
513
- " <th>2023-08-03</th>\n",
514
- " <td>45.746582</td>\n",
515
- " <td>68.619873</td>\n",
516
- " <td>4582.010010</td>\n",
517
- " <td>4501.890137</td>\n",
518
- " </tr>\n",
519
- " </tbody>\n",
520
- "</table>\n",
521
- "<p>1281 rows × 4 columns</p>\n",
522
- "</div>"
523
- ],
524
- "text/plain": [
525
- " VIX_EM VIX_EM_15 VIX_EM_15_High Close\n",
526
- "index \n",
527
- "2018-07-02 NaN NaN NaN 2726.709961\n",
528
- "2018-07-03 26.795587 40.193381 2766.903342 2713.219971\n",
529
- "2018-07-05 27.585969 41.378954 2754.598925 2736.610107\n",
530
- "2018-07-06 25.806818 38.710227 2775.320335 2759.820068\n",
531
- "2018-07-09 23.244055 34.866083 2794.686151 2784.169922\n",
532
- "... ... ... ... ...\n",
533
- "2023-07-28 41.188099 61.782148 4599.192304 4582.229980\n",
534
- "2023-07-31 38.477492 57.716238 4639.946219 4588.959961\n",
535
- "2023-08-01 39.401237 59.101856 4648.061817 4576.729980\n",
536
- "2023-08-02 40.161151 60.241726 4636.971706 4513.390137\n",
537
- "2023-08-03 45.746582 68.619873 4582.010010 4501.890137\n",
538
- "\n",
539
- "[1281 rows x 4 columns]"
540
- ]
541
- },
542
- "execution_count": 33,
543
- "metadata": {},
544
- "output_type": "execute_result"
545
- }
546
- ],
547
  "source": [
548
  "data[['VIX_EM','VIX_EM_15','VIX_EM_15_High','Close']]"
549
  ]
550
  },
551
  {
552
  "cell_type": "code",
553
- "execution_count": 34,
554
  "metadata": {},
555
- "outputs": [
556
- {
557
- "data": {
558
- "text/plain": [
559
- "0.8032786885245902"
560
- ]
561
- },
562
- "execution_count": 34,
563
- "metadata": {},
564
- "output_type": "execute_result"
565
- }
566
- ],
567
  "source": [
568
  "# How often did price close within EM?\n",
569
  "len(data.query('Close <= VIX_EM_High & Close >= VIX_EM_Low')) / len(data)"
@@ -571,20 +628,9 @@
571
  },
572
  {
573
  "cell_type": "code",
574
- "execution_count": 35,
575
  "metadata": {},
576
- "outputs": [
577
- {
578
- "data": {
579
- "text/plain": [
580
- "0.33099141295862605"
581
- ]
582
- },
583
- "execution_count": 35,
584
- "metadata": {},
585
- "output_type": "execute_result"
586
- }
587
- ],
588
  "source": [
589
  "# How often was EM tested?\n",
590
  "len(data.query('High > VIX_EM_High | Low < VIX_EM_Low')) / len(data)"
@@ -592,20 +638,9 @@
592
  },
593
  {
594
  "cell_type": "code",
595
- "execution_count": 40,
596
  "metadata": {},
597
- "outputs": [
598
- {
599
- "data": {
600
- "text/plain": [
601
- "0.8930523028883685"
602
- ]
603
- },
604
- "execution_count": 40,
605
- "metadata": {},
606
- "output_type": "execute_result"
607
- }
608
- ],
609
  "source": [
610
  "# How often did price close within EM?\n",
611
  "len(data.query('Close <= VIX_EM_125_High & Close >= VIX_EM_125_Low')) / len(data)"
@@ -613,20 +648,9 @@
613
  },
614
  {
615
  "cell_type": "code",
616
- "execution_count": 41,
617
  "metadata": {},
618
- "outputs": [
619
- {
620
- "data": {
621
- "text/plain": [
622
- "0.19750195160031225"
623
- ]
624
- },
625
- "execution_count": 41,
626
- "metadata": {},
627
- "output_type": "execute_result"
628
- }
629
- ],
630
  "source": [
631
  "# How often was EM tested?\n",
632
  "len(data.query('High > VIX_EM_125_High | Low < VIX_EM_125_Low')) / len(data)"
@@ -634,20 +658,9 @@
634
  },
635
  {
636
  "cell_type": "code",
637
- "execution_count": 42,
638
  "metadata": {},
639
- "outputs": [
640
- {
641
- "data": {
642
- "text/plain": [
643
- "0.9383294301327089"
644
- ]
645
- },
646
- "execution_count": 42,
647
- "metadata": {},
648
- "output_type": "execute_result"
649
- }
650
- ],
651
  "source": [
652
  "# How often did price close within EM?\n",
653
  "len(data.query('Close <= VIX_EM_15_High & Close >= VIX_EM_15_Low')) / len(data)"
@@ -655,20 +668,9 @@
655
  },
656
  {
657
  "cell_type": "code",
658
- "execution_count": 43,
659
  "metadata": {},
660
- "outputs": [
661
- {
662
- "data": {
663
- "text/plain": [
664
- "0.10772833723653395"
665
- ]
666
- },
667
- "execution_count": 43,
668
- "metadata": {},
669
- "output_type": "execute_result"
670
- }
671
- ],
672
  "source": [
673
  "# How often was EM tested?\n",
674
  "len(data.query('High > VIX_EM_15_High | Low < VIX_EM_15_Low')) / len(data)"
 
4
  "cell_type": "code",
5
  "execution_count": 1,
6
  "metadata": {},
7
+ "outputs": [],
 
 
 
 
 
 
 
 
8
  "source": [
9
  "import pandas as pd\n",
10
  "import numpy as np\n",
11
+ "from model_30m import get_data, walk_forward_validation_seq"
 
12
  ]
13
  },
14
  {
 
20
  "name": "stderr",
21
  "output_type": "stream",
22
  "text": [
23
+ "getting econ tickers: 100%|██████████| 3/3 [00:00<00:00, 4.25it/s]\n",
24
+ "Getting release dates: 100%|██████████| 8/8 [00:01<00:00, 5.09it/s]\n",
25
+ "Making indicators: 100%|██████████| 8/8 [00:00<00:00, 3996.48it/s]\n",
26
+ "Found cached dataset text (C:/Users/WINSTON-ITX/.cache/huggingface/datasets/boomsss___text/boomsss--spx_intra-e0e5e7af8fd43022/0.0.0/cb1e9bd71a82ad27976be3b12b407850fe2837d80c22c5e03a28949843a8ace2)\n",
27
+ "Merging econ data: 100%|██████████| 8/8 [00:00<00:00, 999.09it/s]\n"
28
  ]
29
  }
30
  ],
 
46
  },
47
  {
48
  "cell_type": "code",
49
+ "execution_count": 8,
50
  "metadata": {},
51
  "outputs": [
52
  {
53
  "name": "stderr",
54
  "output_type": "stream",
55
  "text": [
56
+ "LR Model: 100%|██████████| 1223/1223 [00:03<00:00, 367.50it/s]\n",
57
+ "d:\\Projects\\gamedayspx\\model_30m.py:83: SettingWithCopyWarning: \n",
58
  "A value is trying to be set on a copy of a slice from a DataFrame.\n",
59
  "Try using .loc[row_indexer,col_indexer] = value instead\n",
60
  "\n",
61
  "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
62
  " for_merge['RegrModelOut'] = for_merge['RegrModelOut'] > 0\n",
63
+ "CLF Model: 100%|██████████| 1123/1123 [00:08<00:00, 135.03it/s]\n"
64
  ]
65
  }
66
  ],
 
70
  },
71
  {
72
  "cell_type": "code",
73
+ "execution_count": 9,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  "metadata": {},
75
  "outputs": [],
76
  "source": [
77
  "from sklearn.metrics import roc_auc_score, precision_score, recall_score\n",
 
78
  "# st.subheader('New Prediction')\n",
79
+ "nq = 7\n",
80
  "\n",
81
+ "df_probas = res1.groupby(pd.qcut(res1['Predicted'],nq)).agg({'True':[np.mean,len,np.sum]})\n",
82
+ "# df_probas = res1.groupby(pd.cut(res1['Predicted'],[-np.inf, 0.27, 0.375, 0.625, 0.7, np.inf])).agg({'True':[np.mean,len,np.sum]})\n",
83
  "df_probas.columns = ['PctGreen','NumObs','NumGreen']\n",
84
  "\n",
85
+ "# Calculate quantiles\n",
86
+ "quantiles = pd.qcut(res1['Predicted'], nq, labels=False, duplicates='drop')\n",
87
+ "\n",
88
+ "# Determine the number of quantiles\n",
89
+ "num_quantiles = len(quantiles.unique())\n",
90
+ "\n",
91
+ "# Calculate the middle quantile(s)\n",
92
+ "if num_quantiles % 2 == 0: # Even number of quantiles\n",
93
+ " middle_quantiles = quantiles.isin([num_quantiles // 2 - 1, num_quantiles // 2])\n",
94
+ "else: # Odd number of quantiles\n",
95
+ " middle_quantiles = quantiles == num_quantiles // 2\n",
96
+ "\n",
97
+ "# Extract the lower and upper thresholds\n",
98
+ "lo_thres = 0.4 # res1.loc[middle_quantiles, 'Predicted'].min()\n",
99
+ "hi_thres = 0.6 # res1.loc[middle_quantiles, 'Predicted'].max()\n",
100
+ "\n",
101
  "roc_auc_score_all = roc_auc_score(res1['True'].astype(int), res1['Predicted'].values)\n",
102
  "precision_score_all = precision_score(res1['True'].astype(int), res1['Predicted'] > 0.5)\n",
103
  "recall_score_all = recall_score(res1['True'].astype(int), res1['Predicted'] > 0.5)\n",
104
  "len_all = len(res1)\n",
105
  "\n",
106
+ "res2_filtered = res1.loc[(res1['Predicted'] > hi_thres) | (res1['Predicted'] <= lo_thres)]\n",
107
  "\n",
108
  "roc_auc_score_hi = roc_auc_score(res2_filtered['True'].astype(int), res2_filtered['Predicted'].values)\n",
109
  "precision_score_hi = precision_score(res2_filtered['True'].astype(int), res2_filtered['Predicted'] > 0.5)\n",
 
130
  ").round(2)\n",
131
  "\n",
132
  "def get_acc(t, p):\n",
133
+ " if t == False and p <= lo_thres:\n",
134
+ " return '✅' # &#9989;</p>\n",
135
+ " elif t == True and p > hi_thres:\n",
136
+ " return '✅' # \n",
137
+ " elif t == False and p > hi_thres:\n",
138
+ " return '❌' # &#10060;</p>\n",
139
+ " elif t == True and p <= lo_thres:\n",
140
  " return '❌'\n",
141
  " else:\n",
142
+ " return '🟨' # &#11036;</p>\n",
143
+ " \n",
144
+ "def get_acc_html(t, p):\n",
145
+ " if t == False and p <= lo_thres:\n",
146
+ " return '&#9989;'\n",
147
+ " elif t == True and p > hi_thres:\n",
148
+ " return '&#9989;'\n",
149
+ " elif t == False and p > hi_thres:\n",
150
+ " return '&#10060;'\n",
151
+ " elif t == True and p <= lo_thres:\n",
152
+ " return '&#10060;'\n",
153
+ " else:\n",
154
+ " return '&#11036;'\n",
155
+ "\n",
156
  "\n",
157
  "perf_daily = res1.copy()\n",
158
+ "perf_daily['Accuracy'] = [get_acc(t, p) for t, p in zip(perf_daily['True'], perf_daily['Predicted'])]\n",
159
+ "perf_daily['HTML'] = [get_acc_html(t, p) for t, p in zip(perf_daily['True'], perf_daily['Predicted'])]"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  ]
161
  },
162
  {
 
188
  " <th>PctGreen</th>\n",
189
  " <th>NumObs</th>\n",
190
  " <th>NumGreen</th>\n",
 
 
 
191
  " </tr>\n",
192
  " <tr>\n",
193
  " <th>Predicted</th>\n",
194
  " <th></th>\n",
195
  " <th></th>\n",
196
  " <th></th>\n",
 
 
 
197
  " </tr>\n",
198
  " </thead>\n",
199
  " <tbody>\n",
200
  " <tr>\n",
201
+ " <th>(0.19, 0.323]</th>\n",
202
+ " <td>0.149068</td>\n",
203
+ " <td>161</td>\n",
204
  " <td>24</td>\n",
 
 
 
205
  " </tr>\n",
206
  " <tr>\n",
207
+ " <th>(0.323, 0.423]</th>\n",
208
+ " <td>0.225000</td>\n",
209
+ " <td>160</td>\n",
210
+ " <td>36</td>\n",
211
+ " </tr>\n",
212
+ " <tr>\n",
213
+ " <th>(0.423, 0.527]</th>\n",
214
+ " <td>0.450000</td>\n",
215
+ " <td>160</td>\n",
216
+ " <td>72</td>\n",
217
+ " </tr>\n",
218
+ " <tr>\n",
219
+ " <th>(0.527, 0.634]</th>\n",
220
+ " <td>0.602484</td>\n",
221
+ " <td>161</td>\n",
222
+ " <td>97</td>\n",
223
  " </tr>\n",
224
  " <tr>\n",
225
+ " <th>(0.634, 0.707]</th>\n",
226
+ " <td>0.681250</td>\n",
227
+ " <td>160</td>\n",
228
  " <td>109</td>\n",
 
 
 
229
  " </tr>\n",
230
  " <tr>\n",
231
+ " <th>(0.707, 0.773]</th>\n",
232
+ " <td>0.768750</td>\n",
233
+ " <td>160</td>\n",
234
+ " <td>123</td>\n",
 
 
 
235
  " </tr>\n",
236
  " <tr>\n",
237
+ " <th>(0.773, 0.852]</th>\n",
238
+ " <td>0.838509</td>\n",
239
+ " <td>161</td>\n",
240
+ " <td>135</td>\n",
 
 
 
241
  " </tr>\n",
242
  " </tbody>\n",
243
  "</table>\n",
244
  "</div>"
245
  ],
246
  "text/plain": [
247
+ " PctGreen NumObs NumGreen\n",
248
+ "Predicted \n",
249
+ "(0.19, 0.323] 0.149068 161 24\n",
250
+ "(0.323, 0.423] 0.225000 160 36\n",
251
+ "(0.423, 0.527] 0.450000 160 72\n",
252
+ "(0.527, 0.634] 0.602484 161 97\n",
253
+ "(0.634, 0.707] 0.681250 160 109\n",
254
+ "(0.707, 0.773] 0.768750 160 123\n",
255
+ "(0.773, 0.852] 0.838509 161 135"
256
  ]
257
  },
258
  "execution_count": 10,
 
266
  },
267
  {
268
  "cell_type": "code",
269
+ "execution_count": 7,
 
 
 
 
 
 
 
 
 
270
  "metadata": {},
271
  "outputs": [
272
  {
273
  "data": {
274
+ "text/html": [
275
+ "<div>\n",
276
+ "<style scoped>\n",
277
+ " .dataframe tbody tr th:only-of-type {\n",
278
+ " vertical-align: middle;\n",
279
+ " }\n",
280
+ "\n",
281
+ " .dataframe tbody tr th {\n",
282
+ " vertical-align: top;\n",
283
+ " }\n",
284
+ "\n",
285
+ " .dataframe thead th {\n",
286
+ " text-align: right;\n",
287
+ " }\n",
288
+ "</style>\n",
289
+ "<table border=\"1\" class=\"dataframe\">\n",
290
+ " <thead>\n",
291
+ " <tr style=\"text-align: right;\">\n",
292
+ " <th></th>\n",
293
+ " <th>All</th>\n",
294
+ " <th>High Confidence</th>\n",
295
+ " </tr>\n",
296
+ " </thead>\n",
297
+ " <tbody>\n",
298
+ " <tr>\n",
299
+ " <th>N</th>\n",
300
+ " <td>1183.00</td>\n",
301
+ " <td>884.00</td>\n",
302
+ " </tr>\n",
303
+ " <tr>\n",
304
+ " <th>ROC AUC</th>\n",
305
+ " <td>0.79</td>\n",
306
+ " <td>0.81</td>\n",
307
+ " </tr>\n",
308
+ " <tr>\n",
309
+ " <th>Precision</th>\n",
310
+ " <td>0.72</td>\n",
311
+ " <td>0.75</td>\n",
312
+ " </tr>\n",
313
+ " <tr>\n",
314
+ " <th>Recall</th>\n",
315
+ " <td>0.81</td>\n",
316
+ " <td>0.88</td>\n",
317
+ " </tr>\n",
318
+ " </tbody>\n",
319
+ "</table>\n",
320
+ "</div>"
321
+ ],
322
  "text/plain": [
323
+ " All High Confidence\n",
324
+ "N 1183.00 884.00\n",
325
+ "ROC AUC 0.79 0.81\n",
326
+ "Precision 0.72 0.75\n",
327
+ "Recall 0.81 0.88"
328
  ]
329
  },
330
+ "execution_count": 7,
331
+ "metadata": {},
332
+ "output_type": "execute_result"
 
333
  }
334
  ],
335
+ "source": [
336
+ "df_performance"
337
+ ]
338
+ },
339
+ {
340
+ "cell_type": "code",
341
+ "execution_count": null,
342
+ "metadata": {},
343
+ "outputs": [],
344
+ "source": [
345
+ "perf_daily.tail(20)"
346
+ ]
347
+ },
348
+ {
349
+ "cell_type": "code",
350
+ "execution_count": null,
351
+ "metadata": {},
352
+ "outputs": [],
353
+ "source": [
354
+ "import pandas as pd\n",
355
+ "import plotly.graph_objs as go\n",
356
+ "\n",
357
+ "plot_data = perf_daily.merge(data[['Open','High','Low','Close']], left_index=True, right_index=True)\n",
358
+ "\n",
359
+ "df = plot_data.copy()\n",
360
+ "\n",
361
+ "y_min = df['Low'].tail(50).min()\n",
362
+ "y_max = df['High'].tail(50).max()\n",
363
+ "\n",
364
+ "increasing_color = '#3399ff' # Blue\n",
365
+ "decreasing_color = '#ff5f5f' # Red \n",
366
+ "\n",
367
+ "# Create a candlestick trace\n",
368
+ "candlestick_trace = go.Candlestick(\n",
369
+ " x=df.index,\n",
370
+ " open=df['Open'],\n",
371
+ " high=df['High'],\n",
372
+ " low=df['Low'],\n",
373
+ " close=df['Close'],\n",
374
+ " increasing_fillcolor=increasing_color, # Color for increasing candles\n",
375
+ " increasing_line_color=increasing_color, # Color for increasing candles\n",
376
+ " decreasing_fillcolor=decreasing_color, # Color for decreasing candles\n",
377
+ " decreasing_line_color=decreasing_color, # Color for decreasing candles\n",
378
+ " name='OHLC Chart'\n",
379
+ ")\n",
380
+ "\n",
381
+ "# Create a scatter trace for symbols (correct and incorrect)\n",
382
+ "scatter_trace = go.Scatter(\n",
383
+ " x=df.index,\n",
384
+ " y=df['Low'] * 0.995,\n",
385
+ " text=df['HTML'],\n",
386
+ " mode='text',\n",
387
+ " marker=dict(size=10),\n",
388
+ " textposition='bottom center',\n",
389
+ " name='Predictions'\n",
390
+ ")\n",
391
+ "\n",
392
+ "# Create a layout with initial x-axis range for the last 30 candles\n",
393
+ "layout = go.Layout(\n",
394
+ " title='OHLC Chart with Predictions (Right/Wrong)',\n",
395
+ " xaxis=dict(title='Date', range=[df.index[-50], df.index[-1]]), # Set initial range to last 30 data points\n",
396
+ " yaxis=dict(title='Price', range=[y_min, y_max]),\n",
397
+ " xaxis_rangeslider_visible=False,\n",
398
+ " template='plotly_dark'\n",
399
+ ")\n",
400
+ "\n",
401
+ "# Create a figure\n",
402
+ "fig = go.Figure(data=[candlestick_trace, scatter_trace], layout=layout)\n",
403
+ "\n",
404
+ "fig.update_xaxes(\n",
405
+ " rangebreaks=[\n",
406
+ " # NOTE: Below values are bound (not single values), ie. hide x to y\n",
407
+ " dict(bounds=[\"sat\", \"mon\"]), # hide weekends, eg. hide sat to before mon\n",
408
+ " # dict(bounds=[16, 9.5], pattern=\"hour\"), # hide hours outside of 9.30am-4pm\n",
409
+ " # dict(values=[\"2019-12-25\", \"2020-12-24\"]) # hide holidays (Christmas and New Year's, etc)\n",
410
+ " ]\n",
411
+ " )\n",
412
+ "\n",
413
+ "\n",
414
+ "# Show the figure (you can also save it as an HTML file)\n",
415
+ "fig.show()\n"
416
+ ]
417
+ },
418
+ {
419
+ "cell_type": "code",
420
+ "execution_count": null,
421
+ "metadata": {},
422
+ "outputs": [],
423
+ "source": [
424
+ "import mplfinance as mpf\n",
425
+ "\n",
426
+ "# Sample data: assuming you already have df with OHLC data\n",
427
+ "# df['Date'] = df.index\n",
428
+ "# df.set_index('Date', inplace=True)\n",
429
+ "\n",
430
+ "# Determine the data range for the y-axis\n",
431
+ "# y_min = df['Low'].min()\n",
432
+ "# y_max = df['High'].max()\n",
433
+ "\n",
434
+ "df1 = df.tail(50)\n",
435
+ "\n",
436
+ "# Create a custom color map for increasing and decreasing candles\n",
437
+ "mc = mpf.make_marketcolors(\n",
438
+ " up='#3399ff', # Blue for increasing candles\n",
439
+ " down='#ff5f5f', # Red for decreasing candles\n",
440
+ " inherit=True\n",
441
+ ")\n",
442
+ "\n",
443
+ "s = mpf.make_mpf_style(marketcolors=mc,\n",
444
+ " gridcolor='#333333', # Set grid color to match dark background\n",
445
+ " facecolor='#222222', # Set background color to match dark background\n",
446
+ " edgecolor='#222222' # Set edge color to match dark background)\n",
447
+ ")\n",
448
+ "\n",
449
+ "correct = np.where(df1['HTML']=='&#9989;',1, np.nan) * df1['Low'] * 0.997\n",
450
+ "mids = np.where(df1['HTML']=='&#11036;',1, np.nan) * df1['Low'] * 0.997\n",
451
+ "wrongs = np.where(df1['HTML']=='&#10060;',1, np.nan) * df1['Low'] * 0.997\n",
452
+ "\n",
453
+ "\n",
454
+ "# Create an addplot for annotations\n",
455
+ "add_plot = mpf.make_addplot(correct, color='green', sc='green')\n",
456
+ "add_mids = mpf.make_addplot(mids, color='yellow', marker='green')\n",
457
+ "add_wrongs = mpf.make_addplot(wrongs, color='red', marker='green')\n",
458
+ "\n",
459
+ "# Create an OHLC chart with mplfinance\n",
460
+ "mpf.plot(df1, type='candle', style='binance', title='OHLC Chart with Predictions (Right/Wrong)', ylabel='Price',\n",
461
+ " # hlines=dict(hlines=[y_min, y_max], colors=['gray', 'gray']), # Add horizontal lines for y-axis range\n",
462
+ " xrotation=0, # Rotate x-axis labels if needed\n",
463
+ " figratio=(10, 6), # Adjust the figure size as needed\n",
464
+ " volume=False,\n",
465
+ " addplot = [add_plot, add_mids, add_wrongs]) # Disable volume bars\n",
466
+ "\n",
467
+ "\n",
468
+ "# Show the chart"
469
+ ]
470
+ },
471
+ {
472
+ "cell_type": "code",
473
+ "execution_count": null,
474
+ "metadata": {},
475
+ "outputs": [],
476
+ "source": [
477
+ "mpf.available_fonts()"
478
+ ]
479
+ },
480
+ {
481
+ "cell_type": "code",
482
+ "execution_count": null,
483
+ "metadata": {},
484
+ "outputs": [],
485
+ "source": [
486
+ "perf_daily1 = perf_daily.merge(data['ClosePct'], left_index=True, right_index=True)"
487
+ ]
488
+ },
489
+ {
490
+ "cell_type": "code",
491
+ "execution_count": null,
492
+ "metadata": {},
493
+ "outputs": [],
494
+ "source": [
495
+ "res2 = res1.merge(data[['ClosePct','HighPct','LowPct']], left_index=True, right_index=True)"
496
+ ]
497
+ },
498
+ {
499
+ "cell_type": "code",
500
+ "execution_count": null,
501
+ "metadata": {},
502
+ "outputs": [],
503
+ "source": [
504
+ "int_labels = ['(-∞, .20]', '(.20, .40]', '(.40, .60]', '(.60, .80]', '(.80, ∞]']\n",
505
+ "df_probas = res2.groupby(pd.qcut(res2['Predicted'],7)).agg({'True':[np.mean,len,np.sum],'ClosePct':[np.mean, np.std], 'HighPct':[np.mean], 'LowPct':[np.mean]})\n",
506
+ "# df_probas = res2.groupby(pd.cut(res2['Predicted'], bins = [-np.inf, 0.2, 0.4, 0.6, 0.8, np.inf], labels = int_labels)).agg({'True':[np.mean,len,np.sum],'ClosePct':[np.mean], 'HighPct':[np.mean], 'LowPct':[np.mean]})\n",
507
+ "df_probas.columns = ['PctGreen','NumObs','NumGreen','AvgPerf','PerfStD','AvgHigh','AvgLow']"
508
+ ]
509
+ },
510
+ {
511
+ "cell_type": "code",
512
+ "execution_count": null,
513
+ "metadata": {},
514
+ "outputs": [],
515
+ "source": [
516
+ "df_probas"
517
+ ]
518
+ },
519
+ {
520
+ "cell_type": "code",
521
+ "execution_count": null,
522
+ "metadata": {},
523
+ "outputs": [],
524
+ "source": []
525
+ },
526
+ {
527
+ "cell_type": "code",
528
+ "execution_count": null,
529
+ "metadata": {},
530
+ "outputs": [],
531
+ "source": [
532
+ "mean_predicted_value"
533
+ ]
534
+ },
535
+ {
536
+ "cell_type": "code",
537
+ "execution_count": null,
538
+ "metadata": {},
539
+ "outputs": [],
540
+ "source": [
541
+ "res2['Quantile'] = pd.cut(res2['Predicted'], bins = [-np.inf, 0.2, 0.4, 0.6, 0.8, np.inf], labels = int_labels)"
542
+ ]
543
+ },
544
+ {
545
+ "cell_type": "code",
546
+ "execution_count": null,
547
+ "metadata": {},
548
+ "outputs": [],
549
  "source": [
550
  "import matplotlib.pyplot as plt\n",
551
  "\n",
 
577
  },
578
  {
579
  "cell_type": "code",
580
+ "execution_count": null,
581
  "metadata": {},
582
  "outputs": [],
583
  "source": [
 
609
  },
610
  {
611
  "cell_type": "code",
612
+ "execution_count": null,
613
  "metadata": {},
614
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
615
  "source": [
616
  "data[['VIX_EM','VIX_EM_15','VIX_EM_15_High','Close']]"
617
  ]
618
  },
619
  {
620
  "cell_type": "code",
621
+ "execution_count": null,
622
  "metadata": {},
623
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
624
  "source": [
625
  "# How often did price close within EM?\n",
626
  "len(data.query('Close <= VIX_EM_High & Close >= VIX_EM_Low')) / len(data)"
 
628
  },
629
  {
630
  "cell_type": "code",
631
+ "execution_count": null,
632
  "metadata": {},
633
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
634
  "source": [
635
  "# How often was EM tested?\n",
636
  "len(data.query('High > VIX_EM_High | Low < VIX_EM_Low')) / len(data)"
 
638
  },
639
  {
640
  "cell_type": "code",
641
+ "execution_count": null,
642
  "metadata": {},
643
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
644
  "source": [
645
  "# How often did price close within EM?\n",
646
  "len(data.query('Close <= VIX_EM_125_High & Close >= VIX_EM_125_Low')) / len(data)"
 
648
  },
649
  {
650
  "cell_type": "code",
651
+ "execution_count": null,
652
  "metadata": {},
653
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
654
  "source": [
655
  "# How often was EM tested?\n",
656
  "len(data.query('High > VIX_EM_125_High | Low < VIX_EM_125_Low')) / len(data)"
 
658
  },
659
  {
660
  "cell_type": "code",
661
+ "execution_count": null,
662
  "metadata": {},
663
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
664
  "source": [
665
  "# How often did price close within EM?\n",
666
  "len(data.query('Close <= VIX_EM_15_High & Close >= VIX_EM_15_Low')) / len(data)"
 
668
  },
669
  {
670
  "cell_type": "code",
671
+ "execution_count": null,
672
  "metadata": {},
673
+ "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
674
  "source": [
675
  "# How often was EM tested?\n",
676
  "len(data.query('High > VIX_EM_15_High | Low < VIX_EM_15_Low')) / len(data)"