panelbeater 0.0.2__tar.gz → 0.0.3__tar.gz
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.
Potentially problematic release.
This version of panelbeater might be problematic. Click here for more details.
- {panelbeater-0.0.2/panelbeater.egg-info → panelbeater-0.0.3}/PKG-INFO +1 -1
- {panelbeater-0.0.2 → panelbeater-0.0.3}/panelbeater/__init__.py +1 -1
- {panelbeater-0.0.2 → panelbeater-0.0.3}/panelbeater/__main__.py +10 -3
- {panelbeater-0.0.2 → panelbeater-0.0.3}/panelbeater/download.py +1 -5
- {panelbeater-0.0.2 → panelbeater-0.0.3}/panelbeater/features.py +0 -1
- panelbeater-0.0.3/panelbeater/normalizer.py +59 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3/panelbeater.egg-info}/PKG-INFO +1 -1
- {panelbeater-0.0.2 → panelbeater-0.0.3}/setup.py +1 -1
- panelbeater-0.0.2/panelbeater/normalizer.py +0 -21
- {panelbeater-0.0.2 → panelbeater-0.0.3}/LICENSE +0 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3}/MANIFEST.in +0 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3}/README.md +0 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3}/panelbeater.egg-info/SOURCES.txt +0 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3}/panelbeater.egg-info/dependency_links.txt +0 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3}/panelbeater.egg-info/entry_points.txt +0 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3}/panelbeater.egg-info/not-zip-safe +0 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3}/panelbeater.egg-info/requires.txt +0 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3}/panelbeater.egg-info/top_level.txt +0 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3}/requirements.txt +0 -0
- {panelbeater-0.0.2 → panelbeater-0.0.3}/setup.cfg +0 -0
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
import datetime
|
|
4
4
|
|
|
5
5
|
import requests_cache
|
|
6
|
+
import tqdm
|
|
6
7
|
import wavetrainer as wt
|
|
7
8
|
|
|
8
9
|
from .download import download
|
|
9
10
|
from .features import features
|
|
10
|
-
from .normalizer import normalize
|
|
11
|
+
from .normalizer import denormalize, normalize
|
|
11
12
|
|
|
12
13
|
_TICKERS = [
|
|
13
14
|
# Equities
|
|
@@ -46,6 +47,7 @@ _WINDOWS = [
|
|
|
46
47
|
200,
|
|
47
48
|
]
|
|
48
49
|
_LAGS = [1, 3, 5, 10, 20, 30]
|
|
50
|
+
_DAYS_OUT = 30
|
|
49
51
|
|
|
50
52
|
|
|
51
53
|
def main() -> None:
|
|
@@ -61,8 +63,13 @@ def main() -> None:
|
|
|
61
63
|
)
|
|
62
64
|
df_y = download(tickers=_TICKERS, macros=_MACROS, session=session)
|
|
63
65
|
df_x = features(df=df_y.copy(), windows=_WINDOWS, lags=_LAGS)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
df_y_norm = normalize(df=df_y.copy())
|
|
67
|
+
for _ in tqdm.tqdm(range(_DAYS_OUT), desc="Running t+X simulation"):
|
|
68
|
+
wavetrainer.fit(df_x, y=df_y_norm)
|
|
69
|
+
df_next = wavetrainer.transform(df_y_norm)
|
|
70
|
+
df_next = denormalize(df_next)
|
|
71
|
+
df_x = features(df=df_next.copy(), windows=_WINDOWS, lags=_LAGS)
|
|
72
|
+
df_y_norm = normalize(df=df_next.copy())
|
|
66
73
|
|
|
67
74
|
|
|
68
75
|
if __name__ == "__main__":
|
|
@@ -63,8 +63,4 @@ def download(
|
|
|
63
63
|
levels = pd.concat(
|
|
64
64
|
[prices.add_prefix("PX_"), macro.add_prefix("MACRO_")], axis=1
|
|
65
65
|
).ffill()
|
|
66
|
-
return (
|
|
67
|
-
levels.replace([np.inf, -np.inf], np.nan)
|
|
68
|
-
.pct_change(fill_method=None)
|
|
69
|
-
.replace([np.inf, -np.inf], np.nan)
|
|
70
|
-
)
|
|
66
|
+
return levels.replace([np.inf, -np.inf], np.nan)
|
|
@@ -36,7 +36,6 @@ def _meta_ticker_feature(
|
|
|
36
36
|
for window in tqdm.tqdm(windows, desc="Generating window features"):
|
|
37
37
|
dfs.append(df.rolling(window).mean().add_suffix(f"_rmean{window}")) # type: ignore
|
|
38
38
|
dfs.append(df.rolling(window).std().add_suffix(f"_rstd{window}")) # type: ignore
|
|
39
|
-
dfs.append(df.diff().add_suffix("_diff1"))
|
|
40
39
|
return pd.concat(dfs, axis=1).replace([np.inf, -np.inf], np.nan)
|
|
41
40
|
|
|
42
41
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Normalize the Y targets to standard deviations."""
|
|
2
|
+
|
|
3
|
+
# pylint: disable=too-many-locals
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import tqdm
|
|
10
|
+
from wavetrainer.model.model import PROBABILITY_COLUMN_PREFIX
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def normalize(df: pd.DataFrame) -> pd.DataFrame:
|
|
14
|
+
"""Normalize the dataframe per column by z-score bucketing."""
|
|
15
|
+
df = df.pct_change(fill_method=None).replace([np.inf, -np.inf], np.nan)
|
|
16
|
+
mu = df.rolling(365).mean()
|
|
17
|
+
sigma = df.rolling(365).std()
|
|
18
|
+
df = ((((df - mu) / sigma) * 2.0).round() / 2.0).clip(-3, 3)
|
|
19
|
+
dfs = []
|
|
20
|
+
for col in tqdm.tqdm(df.columns, desc="Normalising targets"):
|
|
21
|
+
for unique_val in df[col].unique():
|
|
22
|
+
if math.isnan(unique_val):
|
|
23
|
+
continue
|
|
24
|
+
s = (df[col] == unique_val).rename(f"{col}_{unique_val}")
|
|
25
|
+
dfs.append(s)
|
|
26
|
+
return pd.concat(dfs, axis=1)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def denormalize(df: pd.DataFrame) -> pd.DataFrame:
|
|
30
|
+
"""Denormalize the dataframe back to a total value."""
|
|
31
|
+
date_to_add = df.index[-1] + pd.Timedelta(days=1)
|
|
32
|
+
|
|
33
|
+
cols = set(df.columns.values.tolist())
|
|
34
|
+
target_cols = {x for x in cols if "_".join(x.split("_")[:-1])}
|
|
35
|
+
for col in target_cols:
|
|
36
|
+
df[col] = None
|
|
37
|
+
|
|
38
|
+
# Find the standard deviations
|
|
39
|
+
z_cols = {x for x in cols if x.startswith(col)}
|
|
40
|
+
stds = sorted([float(x.replace(col, "").split("_")[1]) for x in z_cols])
|
|
41
|
+
|
|
42
|
+
# Find the highest probability standard deviation
|
|
43
|
+
highest_std_value = 0.0
|
|
44
|
+
highest_std = None
|
|
45
|
+
for std in stds:
|
|
46
|
+
std_suffix = f"{col}_{std}_{PROBABILITY_COLUMN_PREFIX}"
|
|
47
|
+
std_true_col = sorted([x for x in cols if x.startswith(std_suffix)])[-1]
|
|
48
|
+
std_value = df[std_true_col].iloc[-1]
|
|
49
|
+
if std_value > highest_std_value:
|
|
50
|
+
highest_std_value = std_value
|
|
51
|
+
highest_std = std
|
|
52
|
+
|
|
53
|
+
# Convert the standard deviation back to a value
|
|
54
|
+
mu = df[col].rolling(365).mean()
|
|
55
|
+
sigma = df[col].rolling(365).std()
|
|
56
|
+
value = (highest_std * sigma) + mu
|
|
57
|
+
df.loc[date_to_add, col] = value
|
|
58
|
+
|
|
59
|
+
return df.drop(columns=list(cols))
|
|
@@ -23,7 +23,7 @@ def install_requires() -> typing.List[str]:
|
|
|
23
23
|
|
|
24
24
|
setup(
|
|
25
25
|
name='panelbeater',
|
|
26
|
-
version='0.0.
|
|
26
|
+
version='0.0.3',
|
|
27
27
|
description='A CLI for finding mispriced options.',
|
|
28
28
|
long_description=long_description,
|
|
29
29
|
long_description_content_type='text/markdown',
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"""Normalize the Y targets to standard deviations."""
|
|
2
|
-
|
|
3
|
-
import math
|
|
4
|
-
|
|
5
|
-
import pandas as pd
|
|
6
|
-
import tqdm
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def normalize(df: pd.DataFrame) -> pd.DataFrame:
|
|
10
|
-
"""Normalize the dataframe per column by z-score bucketing."""
|
|
11
|
-
mu = df.rolling(365).mean()
|
|
12
|
-
sigma = df.rolling(365).std()
|
|
13
|
-
df = ((((df - mu) / sigma) * 2.0).round() / 2.0).clip(-3, 3)
|
|
14
|
-
dfs = []
|
|
15
|
-
for col in tqdm.tqdm(df.columns, desc="Normalising targets"):
|
|
16
|
-
for unique_val in df[col].unique():
|
|
17
|
-
if math.isnan(unique_val):
|
|
18
|
-
continue
|
|
19
|
-
s = (df[col] == unique_val).rename(f"{col}_{unique_val}")
|
|
20
|
-
dfs.append(s)
|
|
21
|
-
return pd.concat(dfs, axis=1)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|