dquant 1.2.1__tar.gz → 1.2.2__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.
- {dquant-1.2.1/src/DQuant.egg-info → dquant-1.2.2}/PKG-INFO +1 -1
- {dquant-1.2.1 → dquant-1.2.2}/pyproject.toml +1 -1
- {dquant-1.2.1 → dquant-1.2.2/src/DQuant.egg-info}/PKG-INFO +1 -1
- dquant-1.2.2/src/dquant/metrics.py +8 -0
- {dquant-1.2.1 → dquant-1.2.2}/src/dquant/models.py +55 -20
- dquant-1.2.1/src/dquant/metrics.py +0 -10
- {dquant-1.2.1 → dquant-1.2.2}/LICENSE +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/README.md +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/setup.cfg +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/src/DQuant.egg-info/SOURCES.txt +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/src/DQuant.egg-info/dependency_links.txt +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/src/DQuant.egg-info/requires.txt +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/src/DQuant.egg-info/top_level.txt +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/src/__init__.py +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/src/dquant/__init__.py +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/src/dquant/get_data.py +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/src/dquant/visual.py +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/test/test.py +0 -0
- {dquant-1.2.1 → dquant-1.2.2}/test/test_load.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dquant
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: DQuant is an open-source Python library for automated volatility forecasting of financial time series. It handles all stages of model construction, from raw prices to the final forecast.
|
|
5
5
|
Author: Denis Makarov
|
|
6
6
|
Project-URL: Homepage, https://dquant.space
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dquant
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: DQuant is an open-source Python library for automated volatility forecasting of financial time series. It handles all stages of model construction, from raw prices to the final forecast.
|
|
5
5
|
Author: Denis Makarov
|
|
6
6
|
Project-URL: Homepage, https://dquant.space
|
|
@@ -12,7 +12,7 @@ import numpy as np
|
|
|
12
12
|
import xgboost
|
|
13
13
|
from sklearn.ensemble import GradientBoostingRegressor
|
|
14
14
|
from sklearn.model_selection import train_test_split
|
|
15
|
-
from sklearn.metrics import mean_squared_error, r2_score
|
|
15
|
+
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
|
|
16
16
|
from .metrics import qlike_score
|
|
17
17
|
from sklearn.preprocessing import StandardScaler
|
|
18
18
|
from typing import Tuple
|
|
@@ -72,9 +72,9 @@ class FichEn:
|
|
|
72
72
|
raw_windows_X = []
|
|
73
73
|
raw_windows_y = []
|
|
74
74
|
|
|
75
|
-
for i in range(window_in + 1, len(data) - window_out +
|
|
75
|
+
for i in range(window_in + 1, len(data) - (window_out + 2)):
|
|
76
76
|
x_window = data.iloc[i - window_in: i]
|
|
77
|
-
y_window = data.iloc[i
|
|
77
|
+
y_window = data.iloc[i: i + window_out+1]
|
|
78
78
|
|
|
79
79
|
raw_windows_X.append(x_window)
|
|
80
80
|
raw_windows_y.append(y_window)
|
|
@@ -563,12 +563,15 @@ class FichEn:
|
|
|
563
563
|
|
|
564
564
|
self.train_errors = []
|
|
565
565
|
self.val_errors = []
|
|
566
|
+
self.train_mae = []
|
|
567
|
+
self.val_mae = []
|
|
566
568
|
self.train_qlike = []
|
|
567
569
|
self.val_qlike = []
|
|
568
570
|
self.train_r2 = []
|
|
569
571
|
self.val_r2 = []
|
|
570
572
|
|
|
571
573
|
self.best_val_error = float('inf')
|
|
574
|
+
self.best_val_mae = float('inf')
|
|
572
575
|
self.best_val_qlike = float('inf')
|
|
573
576
|
self.best_r2 = -float('inf')
|
|
574
577
|
self.patience_counter = 0
|
|
@@ -581,6 +584,8 @@ class FichEn:
|
|
|
581
584
|
self.dquantprint(f'{i} trees')
|
|
582
585
|
t_error = 0
|
|
583
586
|
v_error = 0
|
|
587
|
+
t_mae = 0
|
|
588
|
+
v_mae = 0
|
|
584
589
|
t_qlike = 0
|
|
585
590
|
v_qlike = 0
|
|
586
591
|
t_r2 = 0
|
|
@@ -618,6 +623,8 @@ class FichEn:
|
|
|
618
623
|
if i != 1:
|
|
619
624
|
t_error += mean_squared_error(y_h_clean, self.models[h_idx].predict(X_h))
|
|
620
625
|
v_error += mean_squared_error(y_h_v_clean, self.models[h_idx].predict(X_h_v))
|
|
626
|
+
t_mae += mean_absolute_error(y_h_clean, self.models[h_idx].predict(X_h))
|
|
627
|
+
v_mae += mean_absolute_error(y_h_v_clean, self.models[h_idx].predict(X_h_v))
|
|
621
628
|
t_qlike += qlike_score(y_h_clean, self.models[h_idx].predict(X_h))
|
|
622
629
|
v_qlike += qlike_score(y_h_v_clean, self.models[h_idx].predict(X_h_v))
|
|
623
630
|
t_r2 += r2_score(y_h_clean, self.models[h_idx].predict(X_h))
|
|
@@ -625,6 +632,8 @@ class FichEn:
|
|
|
625
632
|
else:
|
|
626
633
|
t_error += mean_squared_error(y_h_clean, model.predict(X_h))
|
|
627
634
|
v_error += mean_squared_error(y_h_v_clean, model.predict(X_h_v))
|
|
635
|
+
t_mae += mean_absolute_error(y_h_clean, model.predict(X_h))
|
|
636
|
+
v_mae += mean_absolute_error(y_h_v_clean, model.predict(X_h_v))
|
|
628
637
|
t_qlike += qlike_score(y_h_clean, model.predict(X_h))
|
|
629
638
|
v_qlike += qlike_score(y_h_v_clean, model.predict(X_h_v))
|
|
630
639
|
t_r2 += r2_score(y_h_clean, model.predict(X_h))
|
|
@@ -633,6 +642,8 @@ class FichEn:
|
|
|
633
642
|
|
|
634
643
|
var_test_error = float(t_error)/horizon
|
|
635
644
|
var_val_error = float(v_error)/horizon
|
|
645
|
+
var_test_mae = float(t_mae) / horizon
|
|
646
|
+
var_val_mae = float(v_mae) / horizon
|
|
636
647
|
var_test_qlike = float(t_qlike) / horizon
|
|
637
648
|
var_val_qlike = float(v_qlike) / horizon
|
|
638
649
|
var_test_r2 = float(t_r2)/horizon
|
|
@@ -640,10 +651,20 @@ class FichEn:
|
|
|
640
651
|
|
|
641
652
|
if self.early_stopping:
|
|
642
653
|
if len(self.val_errors) > 0:
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
654
|
+
if self.loss == "MAE":
|
|
655
|
+
current_min = min(self.val_mae)
|
|
656
|
+
best_so_far = min(self.best_val_mae, current_min)
|
|
657
|
+
no_improvement_count = len(self.val_mae) - self.val_mae.index(best_so_far) - 1
|
|
658
|
+
elif self.loss == "MSE":
|
|
659
|
+
current_min = min(self.val_errors)
|
|
660
|
+
best_so_far = min(self.best_val_error, current_min)
|
|
661
|
+
no_improvement_count = len(self.val_errors) - self.val_errors.index(best_so_far) - 1
|
|
662
|
+
elif self.loss == "QLIKE":
|
|
663
|
+
current_min = min(self.val_qlike)
|
|
664
|
+
best_so_far = min(self.best_val_qlike, current_min)
|
|
665
|
+
no_improvement_count = len(self.val_qlike) - self.val_qlike.index(best_so_far) - 1
|
|
666
|
+
else:
|
|
667
|
+
raise "Unavailable loss function"
|
|
647
668
|
|
|
648
669
|
if no_improvement_count >= self.patience:
|
|
649
670
|
self.dquantprint(f'Early stopping at {i} trees (no improvement for {self.patience} steps)')
|
|
@@ -655,6 +676,8 @@ class FichEn:
|
|
|
655
676
|
|
|
656
677
|
self.train_errors.append(var_test_error)
|
|
657
678
|
self.val_errors.append(var_val_error)
|
|
679
|
+
self.train_mae.append(var_test_mae)
|
|
680
|
+
self.val_mae.append(var_val_mae)
|
|
658
681
|
self.train_qlike.append(var_test_qlike)
|
|
659
682
|
self.val_qlike.append(var_val_qlike)
|
|
660
683
|
self.train_r2.append(var_test_r2)
|
|
@@ -663,6 +686,8 @@ class FichEn:
|
|
|
663
686
|
self.dquantprint('Validation QLIKE: ', var_val_qlike)
|
|
664
687
|
self.dquantprint('Train MSE: ', var_test_error)
|
|
665
688
|
self.dquantprint('Validation MSE: ', var_val_error)
|
|
689
|
+
self.dquantprint('Train MAE: ', var_test_mae)
|
|
690
|
+
self.dquantprint('Validation MAE: ', var_val_mae)
|
|
666
691
|
self.dquantprint('Train r2: ', var_test_r2)
|
|
667
692
|
self.dquantprint('Validation r2: ', var_val_r2)
|
|
668
693
|
self.dquantprint(f"{time.time() - start} seconds spent")
|
|
@@ -1439,7 +1464,8 @@ class FichEn:
|
|
|
1439
1464
|
|
|
1440
1465
|
|
|
1441
1466
|
class VolClustGB(FichEn):
|
|
1442
|
-
def __init__(self, sett, early_stopping=True, output=True):
|
|
1467
|
+
def __init__(self, sett, early_stopping=True, output=True, loss="MAE"):
|
|
1468
|
+
self.loss = loss
|
|
1443
1469
|
self.output = output
|
|
1444
1470
|
self.models = []
|
|
1445
1471
|
self.scaler = StandardScaler()
|
|
@@ -1462,7 +1488,8 @@ class VolClustGB(FichEn):
|
|
|
1462
1488
|
}
|
|
1463
1489
|
self.meta = {
|
|
1464
1490
|
"model_type": "gb",
|
|
1465
|
-
"model_settings": self.default_sett
|
|
1491
|
+
"model_settings": self.default_sett,
|
|
1492
|
+
"model_loss": loss
|
|
1466
1493
|
}
|
|
1467
1494
|
if sett == {}:
|
|
1468
1495
|
self.base_model = GradientBoostingRegressor(**self.default_sett)
|
|
@@ -1599,7 +1626,8 @@ class VolClustGB(FichEn):
|
|
|
1599
1626
|
|
|
1600
1627
|
|
|
1601
1628
|
class VolClustXGB(FichEn):
|
|
1602
|
-
def __init__(self, sett, early_stopping=True, output=True,
|
|
1629
|
+
def __init__(self, sett, early_stopping=True, output=True, loss="QLIKE"):
|
|
1630
|
+
self.loss = loss
|
|
1603
1631
|
self.output = output
|
|
1604
1632
|
self.models = []
|
|
1605
1633
|
self.scaler = StandardScaler()
|
|
@@ -1623,15 +1651,18 @@ class VolClustXGB(FichEn):
|
|
|
1623
1651
|
'device': 'cpu'
|
|
1624
1652
|
}
|
|
1625
1653
|
|
|
1626
|
-
if
|
|
1654
|
+
if loss == "MSE":
|
|
1627
1655
|
self.default_sett['objective'] = 'reg:squarederror'
|
|
1656
|
+
elif loss == "MAE":
|
|
1657
|
+
self.default_sett['objective'] = 'reg:absoluteerror'
|
|
1628
1658
|
|
|
1629
1659
|
self.meta = {
|
|
1630
1660
|
"model_type": "xgb",
|
|
1631
|
-
"model_settings": self.default_sett
|
|
1661
|
+
"model_settings": self.default_sett,
|
|
1662
|
+
"model_loss": loss
|
|
1632
1663
|
}
|
|
1633
1664
|
if sett == {}:
|
|
1634
|
-
if
|
|
1665
|
+
if loss == "QLIKE":
|
|
1635
1666
|
self.base_model = xgboost.XGBRegressor(**self.default_sett, objective=self.qlike_obj)
|
|
1636
1667
|
else:
|
|
1637
1668
|
self.base_model = xgboost.XGBRegressor(**self.default_sett)
|
|
@@ -1640,7 +1671,7 @@ class VolClustXGB(FichEn):
|
|
|
1640
1671
|
if sett['objective']: del sett['objective']
|
|
1641
1672
|
except KeyError:
|
|
1642
1673
|
pass
|
|
1643
|
-
if
|
|
1674
|
+
if loss == "QLIKE":
|
|
1644
1675
|
self.base_model = xgboost.XGBRegressor(**sett, objective=self.qlike_obj)
|
|
1645
1676
|
else:
|
|
1646
1677
|
self.base_model = xgboost.XGBRegressor(**sett)
|
|
@@ -1772,7 +1803,8 @@ class VolClustXGB(FichEn):
|
|
|
1772
1803
|
|
|
1773
1804
|
|
|
1774
1805
|
class VolClustLightGBM(FichEn):
|
|
1775
|
-
def __init__(self, sett, early_stopping=True, output=True,
|
|
1806
|
+
def __init__(self, sett, early_stopping=True, output=True, loss="QLIKE"):
|
|
1807
|
+
self.loss = loss
|
|
1776
1808
|
self.output = output
|
|
1777
1809
|
self.models = []
|
|
1778
1810
|
self.scaler = StandardScaler()
|
|
@@ -1798,15 +1830,18 @@ class VolClustLightGBM(FichEn):
|
|
|
1798
1830
|
'boosting_type': 'gbdt'
|
|
1799
1831
|
}
|
|
1800
1832
|
|
|
1801
|
-
if
|
|
1802
|
-
self.default_sett['objective'] = '
|
|
1833
|
+
if loss == "MSE":
|
|
1834
|
+
self.default_sett['objective'] = 'mse'
|
|
1835
|
+
elif loss == "MAE":
|
|
1836
|
+
self.default_sett['objective'] = 'mae'
|
|
1803
1837
|
|
|
1804
1838
|
self.meta = {
|
|
1805
1839
|
"model_type": "lgbm",
|
|
1806
|
-
"model_settings": self.default_sett
|
|
1840
|
+
"model_settings": self.default_sett,
|
|
1841
|
+
"models_loss": loss
|
|
1807
1842
|
}
|
|
1808
1843
|
if sett == {}:
|
|
1809
|
-
if
|
|
1844
|
+
if loss == "QLIKE":
|
|
1810
1845
|
self.base_model = lgb.LGBMRegressor(**self.default_sett, objective=self.qlike_obj)
|
|
1811
1846
|
else:
|
|
1812
1847
|
self.base_model = lgb.LGBMRegressor(**self.default_sett)
|
|
@@ -1815,7 +1850,7 @@ class VolClustLightGBM(FichEn):
|
|
|
1815
1850
|
if sett['objective']: del sett['objective']
|
|
1816
1851
|
except KeyError:
|
|
1817
1852
|
pass
|
|
1818
|
-
if
|
|
1853
|
+
if loss == "QLIKE":
|
|
1819
1854
|
self.base_model = lgb.LGBMRegressor(**sett, objective=self.qlike_obj)
|
|
1820
1855
|
else:
|
|
1821
1856
|
self.base_model = lgb.LGBMRegressor(**sett)
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def qlike_score(y_true, y_pred):
|
|
5
|
-
y_true = np.asarray(y_true, dtype=np.float64)
|
|
6
|
-
y_pred = np.asarray(y_pred, dtype=np.float64)
|
|
7
|
-
eps = 1e-10
|
|
8
|
-
y_pred = np.clip(y_pred, eps, None)
|
|
9
|
-
loss = np.log(y_pred) + y_true / y_pred
|
|
10
|
-
return np.mean(loss)
|
|
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
|
|
File without changes
|
|
File without changes
|