mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-14 08:16:54 +08:00
Merge branch 'main' of https://github.com/you-n-g/qlib into main
This commit is contained in:
@@ -10,6 +10,28 @@ from inspect import getfullargspec
|
||||
import copy
|
||||
|
||||
|
||||
def check_transform_proc(proc_l, fit_start_time, fit_end_time):
|
||||
new_l = []
|
||||
for p in proc_l:
|
||||
if not isinstance(p, Processor):
|
||||
klass, pkwargs = get_cls_kwargs(p, processor_module)
|
||||
args = getfullargspec(klass).args
|
||||
if "fit_start_time" in args and "fit_end_time" in args:
|
||||
assert (
|
||||
fit_start_time is not None and fit_end_time is not None
|
||||
), "Make sure `fit_start_time` and `fit_end_time` are not None."
|
||||
pkwargs.update(
|
||||
{
|
||||
"fit_start_time": fit_start_time,
|
||||
"fit_end_time": fit_end_time,
|
||||
}
|
||||
)
|
||||
new_l.append({"class": klass.__name__, "kwargs": pkwargs})
|
||||
else:
|
||||
new_l.append(p)
|
||||
return new_l
|
||||
|
||||
|
||||
class ALPHA360_Denoise(DataHandlerLP):
|
||||
def __init__(self, instruments="csi500", start_time=None, end_time=None, fit_start_time=None, fit_end_time=None):
|
||||
data_loader = {
|
||||
@@ -83,8 +105,31 @@ class ALPHA360_Denoise(DataHandlerLP):
|
||||
return fields, names
|
||||
|
||||
|
||||
_DEFAULT_LEARN_PROCESSORS = [
|
||||
{"class": "DropnaLabel"},
|
||||
{"class": "CSZScoreNorm", "kwargs": {"fields_group": "label"}},
|
||||
]
|
||||
_DEFAULT_INFER_PROCESSORS = [
|
||||
{"class": "ProcessInf", "kwargs": {}},
|
||||
{"class": "ZScoreNorm", "kwargs": {}},
|
||||
{"class": "Fillna", "kwargs": {}},
|
||||
]
|
||||
|
||||
|
||||
class ALPHA360(DataHandlerLP):
|
||||
def __init__(self, instruments="csi500", start_time=None, end_time=None, fit_start_time=None, fit_end_time=None):
|
||||
def __init__(
|
||||
self,
|
||||
instruments="csi500",
|
||||
start_time=None,
|
||||
end_time=None,
|
||||
infer_processors=_DEFAULT_INFER_PROCESSORS,
|
||||
learn_processors=_DEFAULT_LEARN_PROCESSORS,
|
||||
fit_start_time=None,
|
||||
fit_end_time=None,
|
||||
):
|
||||
infer_processors = check_transform_proc(infer_processors, fit_start_time, fit_end_time)
|
||||
learn_processors = check_transform_proc(learn_processors, fit_start_time, fit_end_time)
|
||||
|
||||
data_loader = {
|
||||
"class": "QlibDataLoader",
|
||||
"kwargs": {
|
||||
@@ -95,16 +140,6 @@ class ALPHA360(DataHandlerLP):
|
||||
},
|
||||
}
|
||||
|
||||
learn_processors = [
|
||||
{"class": "DropnaLabel", "kwargs": {"fields_group": "label"}},
|
||||
{"class": "CSZScoreNorm", "kwargs": {"fields_group": "label"}},
|
||||
]
|
||||
infer_processors = [
|
||||
{"class": "ProcessInf", "kwargs": {}},
|
||||
{"class": "ZscoreNorm", "kwargs": {"fit_start_time": fit_start_time, "fit_end_time": fit_end_time}},
|
||||
{"class": "Fillna", "kwargs": {}},
|
||||
]
|
||||
|
||||
super().__init__(
|
||||
instruments,
|
||||
start_time,
|
||||
@@ -168,33 +203,12 @@ class Alpha158(DataHandlerLP):
|
||||
start_time=None,
|
||||
end_time=None,
|
||||
infer_processors=[],
|
||||
learn_processors=["DropnaLabel", {"class": "CSZScoreNorm", "kwargs": {"fields_group": "label"}}],
|
||||
learn_processors=_DEFAULT_LEARN_PROCESSORS,
|
||||
fit_start_time=None,
|
||||
fit_end_time=None,
|
||||
):
|
||||
def check_transform_proc(proc_l):
|
||||
new_l = []
|
||||
for p in proc_l:
|
||||
if not isinstance(p, Processor):
|
||||
klass, pkwargs = get_cls_kwargs(p, processor_module)
|
||||
args = getfullargspec(klass).args
|
||||
if "fit_start_time" in args and "fit_end_time" in args:
|
||||
assert (
|
||||
fit_start_time is not None and fit_end_time is not None
|
||||
), "Make sure `fit_start_time` and `fit_end_time` are not None."
|
||||
pkwargs.update(
|
||||
{
|
||||
"fit_start_time": fit_start_time,
|
||||
"fit_end_time": fit_end_time,
|
||||
}
|
||||
)
|
||||
new_l.append({"class": klass.__name__, "kwargs": pkwargs})
|
||||
else:
|
||||
new_l.append(p)
|
||||
return new_l
|
||||
|
||||
infer_processors = check_transform_proc(infer_processors)
|
||||
learn_processors = check_transform_proc(learn_processors)
|
||||
infer_processors = check_transform_proc(infer_processors, fit_start_time, fit_end_time)
|
||||
learn_processors = check_transform_proc(learn_processors, fit_start_time, fit_end_time)
|
||||
|
||||
data_loader = {
|
||||
"class": "QlibDataLoader",
|
||||
|
||||
@@ -26,9 +26,9 @@ def risk_analysis(r, N=252):
|
||||
Parameters
|
||||
----------
|
||||
r : pandas.Series
|
||||
daily return series
|
||||
daily return series.
|
||||
N: int
|
||||
scaler for annualizing information_ratio (day: 250, week: 50, month: 12)
|
||||
scaler for annualizing information_ratio (day: 250, week: 50, month: 12).
|
||||
"""
|
||||
mean = r.mean()
|
||||
std = r.std(ddof=1)
|
||||
@@ -61,7 +61,7 @@ def get_strategy(
|
||||
----------
|
||||
|
||||
strategy : Strategy()
|
||||
strategy used in backtest
|
||||
strategy used in backtest.
|
||||
topk : int (Default value: 50)
|
||||
top-N stocks to buy.
|
||||
margin : int or float(Default value: 0.5)
|
||||
@@ -73,14 +73,14 @@ def get_strategy(
|
||||
|
||||
sell_limit = pred_in_a_day.count() * margin
|
||||
|
||||
buffer margin, in single score_mode, continue holding stock if it is in nlargest(sell_limit)
|
||||
sell_limit should be no less than topk
|
||||
buffer margin, in single score_mode, continue holding stock if it is in nlargest(sell_limit).
|
||||
sell_limit should be no less than topk.
|
||||
n_drop : int
|
||||
number of stocks to be replaced in each trading date
|
||||
number of stocks to be replaced in each trading date.
|
||||
risk_degree: float
|
||||
0-1, 0.95 for example, use 95% money to trade
|
||||
0-1, 0.95 for example, use 95% money to trade.
|
||||
str_type: 'amount', 'weight' or 'dropout'
|
||||
strategy type: TopkAmountStrategy ,TopkWeightStrategy or TopkDropoutStrategy
|
||||
strategy type: TopkAmountStrategy ,TopkWeightStrategy or TopkDropoutStrategy.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -126,21 +126,21 @@ def get_exchange(
|
||||
----------
|
||||
|
||||
# exchange related arguments
|
||||
exchange: Exchange()
|
||||
exchange: Exchange().
|
||||
subscribe_fields: list
|
||||
subscribe fields
|
||||
subscribe fields.
|
||||
open_cost : float
|
||||
open transaction cost
|
||||
open transaction cost.
|
||||
close_cost : float
|
||||
close transaction cost
|
||||
close transaction cost.
|
||||
min_cost : float
|
||||
min transaction cost
|
||||
min transaction cost.
|
||||
trade_unit : int
|
||||
100 for China A
|
||||
100 for China A.
|
||||
deal_price: str
|
||||
dealing price type: 'close', 'open', 'vwap'
|
||||
dealing price type: 'close', 'open', 'vwap'.
|
||||
limit_threshold : float
|
||||
limit move 0.1 (10%) for example, long and short with same limit
|
||||
limit move 0.1 (10%) for example, long and short with same limit.
|
||||
extract_codes: bool
|
||||
will we pass the codes extracted from the pred to the exchange.
|
||||
NOTE: This will be faster with offline qlib.
|
||||
@@ -193,20 +193,20 @@ def backtest(pred, account=1e9, shift=1, benchmark="SH000905", verbose=True, **k
|
||||
- **backtest workflow related or commmon arguments**
|
||||
|
||||
pred : pandas.DataFrame
|
||||
predict should has <datetime, instrument> index and one `score` column
|
||||
predict should has <datetime, instrument> index and one `score` column.
|
||||
account : float
|
||||
init account value
|
||||
init account value.
|
||||
shift : int
|
||||
whether to shift prediction by one day
|
||||
whether to shift prediction by one day.
|
||||
benchmark : str
|
||||
benchmark code, default is SH000905 CSI 500
|
||||
benchmark code, default is SH000905 CSI 500.
|
||||
verbose : bool
|
||||
whether to print log
|
||||
whether to print log.
|
||||
|
||||
- **strategy related arguments**
|
||||
|
||||
strategy : Strategy()
|
||||
strategy used in backtest
|
||||
strategy used in backtest.
|
||||
topk : int (Default value: 50)
|
||||
top-N stocks to buy.
|
||||
margin : int or float(Default value: 0.5)
|
||||
@@ -218,33 +218,33 @@ def backtest(pred, account=1e9, shift=1, benchmark="SH000905", verbose=True, **k
|
||||
|
||||
sell_limit = pred_in_a_day.count() * margin
|
||||
|
||||
buffer margin, in single score_mode, continue holding stock if it is in nlargest(sell_limit)
|
||||
sell_limit should be no less than topk
|
||||
buffer margin, in single score_mode, continue holding stock if it is in nlargest(sell_limit).
|
||||
sell_limit should be no less than topk.
|
||||
n_drop : int
|
||||
number of stocks to be replaced in each trading date
|
||||
number of stocks to be replaced in each trading date.
|
||||
risk_degree: float
|
||||
0-1, 0.95 for example, use 95% money to trade
|
||||
0-1, 0.95 for example, use 95% money to trade.
|
||||
str_type: 'amount', 'weight' or 'dropout'
|
||||
strategy type: TopkAmountStrategy ,TopkWeightStrategy or TopkDropoutStrategy
|
||||
strategy type: TopkAmountStrategy ,TopkWeightStrategy or TopkDropoutStrategy.
|
||||
|
||||
- **exchange related arguments**
|
||||
|
||||
exchange: Exchange()
|
||||
pass the exchange for speeding up.
|
||||
subscribe_fields: list
|
||||
subscribe fields
|
||||
subscribe fields.
|
||||
open_cost : float
|
||||
open transaction cost. The default value is 0.002(0.2%).
|
||||
close_cost : float
|
||||
close transaction cost. The default value is 0.002(0.2%).
|
||||
min_cost : float
|
||||
min transaction cost
|
||||
min transaction cost.
|
||||
trade_unit : int
|
||||
100 for China A
|
||||
100 for China A.
|
||||
deal_price: str
|
||||
dealing price type: 'close', 'open', 'vwap'
|
||||
dealing price type: 'close', 'open', 'vwap'.
|
||||
limit_threshold : float
|
||||
limit move 0.1 (10%) for example, long and short with same limit
|
||||
limit move 0.1 (10%) for example, long and short with same limit.
|
||||
extract_codes: bool
|
||||
will we pass the codes extracted from the pred to the exchange.
|
||||
|
||||
@@ -291,17 +291,17 @@ def long_short_backtest(
|
||||
"""
|
||||
A backtest for long-short strategy
|
||||
|
||||
:param pred: The trading signal produced on day `T`
|
||||
:param topk: The short topk securities and long topk securities
|
||||
:param deal_price: The price to deal the trading
|
||||
:param pred: The trading signal produced on day `T`.
|
||||
:param topk: The short topk securities and long topk securities.
|
||||
:param deal_price: The price to deal the trading.
|
||||
:param shift: Whether to shift prediction by one day. The trading day will be T+1 if shift==1.
|
||||
:param open_cost: open transaction cost
|
||||
:param close_cost: close transaction cost
|
||||
:param trade_unit: 100 for China A
|
||||
:param limit_threshold: limit move 0.1 (10%) for example, long and short with same limit
|
||||
:param min_cost: min transaction cost
|
||||
:param subscribe_fields: subscribe fields
|
||||
:param extract_codes: bool
|
||||
:param open_cost: open transaction cost.
|
||||
:param close_cost: close transaction cost.
|
||||
:param trade_unit: 100 for China A.
|
||||
:param limit_threshold: limit move 0.1 (10%) for example, long and short with same limit.
|
||||
:param min_cost: min transaction cost.
|
||||
:param subscribe_fields: subscribe fields.
|
||||
:param extract_codes: bool.
|
||||
will we pass the codes extracted from the pred to the exchange.
|
||||
NOTE: This will be faster with offline qlib.
|
||||
:return: The result of backtest, it is represented by a dict.
|
||||
|
||||
@@ -34,14 +34,14 @@ class CatBoostModel(Model):
|
||||
def fit(
|
||||
self,
|
||||
dataset: DatasetH,
|
||||
num_boost_round=1000,
|
||||
early_stopping_rounds=50,
|
||||
verbose_eval=20,
|
||||
evals_result=dict(),
|
||||
num_boost_round = 1000,
|
||||
early_stopping_rounds = 50,
|
||||
verbose_eval = 20,
|
||||
evals_result = dict(),
|
||||
**kwargs
|
||||
):
|
||||
df_train, df_valid = dataset.prepare(
|
||||
["train", "valid"], col_set=["feature", "label"], data_key=DataHandlerLP.DK_L
|
||||
["train", "valid"], col_set = ["feature", "label"], data_key = DataHandlerLP.DK_L
|
||||
)
|
||||
x_train, y_train = df_train["feature"], df_train["label"]
|
||||
x_valid, y_valid = df_valid["feature"], df_valid["label"]
|
||||
@@ -52,8 +52,8 @@ class CatBoostModel(Model):
|
||||
else:
|
||||
raise ValueError("CatBoost doesn't support multi-label training")
|
||||
|
||||
train_pool = Pool(data=x_train, label=y_train_1d)
|
||||
valid_pool = Pool(data=x_valid, label=y_valid_1d)
|
||||
train_pool = Pool(data = x_train, label = y_train_1d)
|
||||
valid_pool = Pool(data = x_valid, label = y_valid_1d)
|
||||
|
||||
# Initialize the catboost model
|
||||
self._params["iterations"] = num_boost_round
|
||||
@@ -63,7 +63,7 @@ class CatBoostModel(Model):
|
||||
self.model = CatBoost(self._params, **kwargs)
|
||||
|
||||
# train the model
|
||||
self.model.fit(train_pool, eval_set=valid_pool, use_best_model=True, **kwargs)
|
||||
self.model.fit(train_pool, eval_set = valid_pool, use_best_model = True, **kwargs)
|
||||
|
||||
evals_result = self.model.get_evals_result()
|
||||
evals_result["train"] = list(evals_result["learn"].values())[0]
|
||||
@@ -72,8 +72,8 @@ class CatBoostModel(Model):
|
||||
def predict(self, dataset):
|
||||
if self.model is None:
|
||||
raise ValueError("model is not fitted yet!")
|
||||
x_test = dataset.prepare("test", col_set="feature")
|
||||
return pd.Series(self.model.predict(x_test.values), index=x_test.index)
|
||||
x_test = dataset.prepare("test", col_set = "feature")
|
||||
return pd.Series(self.model.predict(x_test.values), index = x_test.index)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -28,14 +28,12 @@ class GAT(Model):
|
||||
|
||||
Parameters
|
||||
----------
|
||||
input_dim : int
|
||||
input dimension
|
||||
output_dim : int
|
||||
output dimension
|
||||
layers : tuple
|
||||
layer sizes
|
||||
lr : float
|
||||
learning rate
|
||||
d_feat : int
|
||||
input dimensions for each time step
|
||||
metric : str
|
||||
the evaluate metric used in early stop
|
||||
optimizer : str
|
||||
optimizer name
|
||||
GPU : str
|
||||
@@ -119,11 +117,7 @@ class GAT(Model):
|
||||
seed,
|
||||
)
|
||||
)
|
||||
|
||||
if loss not in {"mse", "binary"}:
|
||||
raise NotImplementedError("loss {} is not supported!".format(loss))
|
||||
self._scorer = mean_squared_error if loss == "mse" else roc_auc_score
|
||||
|
||||
|
||||
self.GAT_model = GATModel(
|
||||
d_feat=self.d_feat,
|
||||
hidden_size=self.hidden_size,
|
||||
@@ -213,7 +207,6 @@ class GAT(Model):
|
||||
losses = []
|
||||
|
||||
indices = np.arange(len(x_values))
|
||||
np.random.shuffle(indices)
|
||||
|
||||
for i in range(len(indices))[:: self.batch_size]:
|
||||
|
||||
@@ -377,7 +370,6 @@ class GATModel(nn.Module):
|
||||
self.fc_out = nn.Linear(hidden_size, 1)
|
||||
self.leaky_relu = nn.LeakyReLU()
|
||||
self.softmax = nn.Softmax(dim=1)
|
||||
|
||||
self.d_feat = d_feat
|
||||
|
||||
def cal_convariance(self, x, y): # the 2nd dimension of x and y are the same
|
||||
@@ -396,12 +388,7 @@ class GATModel(nn.Module):
|
||||
out, _ = self.rnn(x)
|
||||
hidden = out[:, -1, :]
|
||||
hidden = self.bn1(hidden)
|
||||
|
||||
gamma = self.cal_convariance(hidden, hidden)
|
||||
# gamma = hidden.mm(torch.t(hidden))
|
||||
# gamma = self.leaky_relu(gamma)
|
||||
# gamma = self.softmax(gamma)
|
||||
# gamma = gamma * (torch.ones(x.shape[0], x.shape[0]).to(device) - torch.diag(torch.ones(x.shape[0])).to(device))
|
||||
output = gamma.mm(hidden)
|
||||
output = self.fc(output)
|
||||
output = self.bn2(output)
|
||||
|
||||
@@ -28,14 +28,10 @@ class GRU(Model):
|
||||
|
||||
Parameters
|
||||
----------
|
||||
input_dim : int
|
||||
input dimension
|
||||
output_dim : int
|
||||
output dimension
|
||||
layers : tuple
|
||||
layer sizes
|
||||
lr : float
|
||||
learning rate
|
||||
d_feat : int
|
||||
input dimension for each time step
|
||||
metric: str
|
||||
the evaluate metric used in early stop
|
||||
optimizer : str
|
||||
optimizer name
|
||||
GPU : str
|
||||
@@ -112,10 +108,6 @@ class GRU(Model):
|
||||
)
|
||||
)
|
||||
|
||||
if loss not in {"mse", "binary"}:
|
||||
raise NotImplementedError("loss {} is not supported!".format(loss))
|
||||
self._scorer = mean_squared_error if loss == "mse" else roc_auc_score
|
||||
|
||||
self.gru_model = GRUModel(
|
||||
d_feat=self.d_feat, hidden_size=self.hidden_size, num_layers=self.num_layers, dropout=self.dropout
|
||||
)
|
||||
@@ -251,7 +243,6 @@ class GRU(Model):
|
||||
# train
|
||||
self.logger.info("training...")
|
||||
self._fitted = True
|
||||
# return
|
||||
|
||||
for step in range(self.n_epochs):
|
||||
self.logger.info("Epoch%d:", step)
|
||||
|
||||
@@ -28,14 +28,10 @@ class LSTM(Model):
|
||||
|
||||
Parameters
|
||||
----------
|
||||
input_dim : int
|
||||
input dimension
|
||||
output_dim : int
|
||||
output dimension
|
||||
layers : tuple
|
||||
layer sizes
|
||||
lr : float
|
||||
learning rate
|
||||
d_feat : int
|
||||
input dimension for each time step
|
||||
metric: str
|
||||
the evaluate metric used in early stop
|
||||
optimizer : str
|
||||
optimizer name
|
||||
GPU : str
|
||||
@@ -112,10 +108,6 @@ class LSTM(Model):
|
||||
)
|
||||
)
|
||||
|
||||
if loss not in {"mse", "binary"}:
|
||||
raise NotImplementedError("loss {} is not supported!".format(loss))
|
||||
self._scorer = mean_squared_error if loss == "mse" else roc_auc_score
|
||||
|
||||
self.lstm_model = LSTMModel(
|
||||
d_feat=self.d_feat, hidden_size=self.hidden_size, num_layers=self.num_layers, dropout=self.dropout
|
||||
)
|
||||
@@ -251,7 +243,6 @@ class LSTM(Model):
|
||||
# train
|
||||
self.logger.info("training...")
|
||||
self._fitted = True
|
||||
# return
|
||||
|
||||
for step in range(self.n_epochs):
|
||||
self.logger.info("Epoch%d:", step)
|
||||
|
||||
@@ -22,25 +22,23 @@ from ...data.dataset.handler import DataHandlerLP
|
||||
class XGBModel(Model):
|
||||
"""XGBModel Model"""
|
||||
|
||||
def __init__(self, obj="mse", **kwargs):
|
||||
if obj not in {"mse", "binary"}:
|
||||
raise NotImplementedError
|
||||
self._params = {"obj": obj}
|
||||
def __init__(self, **kwargs):
|
||||
self._params = {}
|
||||
self._params.update(kwargs)
|
||||
self.model = None
|
||||
|
||||
def fit(
|
||||
self,
|
||||
dataset: DatasetH,
|
||||
num_boost_round=1000,
|
||||
early_stopping_rounds=50,
|
||||
verbose_eval=20,
|
||||
evals_result=dict(),
|
||||
num_boost_round = 1000,
|
||||
early_stopping_rounds = 50,
|
||||
verbose_eval = 20,
|
||||
evals_result = dict(),
|
||||
**kwargs
|
||||
):
|
||||
|
||||
df_train, df_valid = dataset.prepare(
|
||||
["train", "valid"], col_set=["feature", "label"], data_key=DataHandlerLP.DK_L
|
||||
["train", "valid"], col_set = ["feature", "label"], data_key = DataHandlerLP.DK_L
|
||||
)
|
||||
x_train, y_train = df_train["feature"], df_train["label"]
|
||||
x_valid, y_valid = df_valid["feature"], df_valid["label"]
|
||||
@@ -51,16 +49,16 @@ class XGBModel(Model):
|
||||
else:
|
||||
raise ValueError("XGBoost doesn't support multi-label training")
|
||||
|
||||
dtrain = xgb.DMatrix(x_train.values, label=y_train_1d)
|
||||
dvalid = xgb.DMatrix(x_valid.values, label=y_valid_1d)
|
||||
dtrain = xgb.DMatrix(x_train.values, label = y_train_1d)
|
||||
dvalid = xgb.DMatrix(x_valid.values, label = y_valid_1d)
|
||||
self.model = xgb.train(
|
||||
self._params,
|
||||
dtrain=dtrain,
|
||||
num_boost_round=num_boost_round,
|
||||
evals=[(dtrain, "train"), (dvalid, "valid")],
|
||||
early_stopping_rounds=early_stopping_rounds,
|
||||
verbose_eval=verbose_eval,
|
||||
evals_result=evals_result,
|
||||
dtrain = dtrain,
|
||||
num_boost_round = num_boost_round,
|
||||
evals = [(dtrain, "train"), (dvalid, "valid")],
|
||||
early_stopping_rounds = early_stopping_rounds,
|
||||
verbose_eval = verbose_eval,
|
||||
evals_result = evals_result,
|
||||
**kwargs
|
||||
)
|
||||
evals_result["train"] = list(evals_result["train"].values())[0]
|
||||
@@ -69,5 +67,5 @@ class XGBModel(Model):
|
||||
def predict(self, dataset):
|
||||
if self.model is None:
|
||||
raise ValueError("model is not fitted yet!")
|
||||
x_test = dataset.prepare("test", col_set="feature")
|
||||
return pd.Series(self.model.predict(xgb.DMatrix(x_test.values)), index=x_test.index)
|
||||
x_test = dataset.prepare("test", col_set = "feature")
|
||||
return pd.Series(self.model.predict(xgb.DMatrix(x_test.values)), index = x_test.index)
|
||||
|
||||
@@ -252,7 +252,7 @@ def model_performance_graph(
|
||||
"""Model performance
|
||||
|
||||
:param pred_label: index is **pd.MultiIndex**, index name is **[instrument, datetime]**; columns names is **[score,
|
||||
label]**. It is usually same as the label of model training(e.g. "Ref($close, -2)/Ref($close, -1) - 1")
|
||||
label]**. It is usually same as the label of model training(e.g. "Ref($close, -2)/Ref($close, -1) - 1").
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
@@ -266,13 +266,13 @@ def model_performance_graph(
|
||||
|
||||
|
||||
:param lag: `pred.groupby(level='instrument')['score'].shift(lag)`. It will be only used in the auto-correlation computing.
|
||||
:param N: group number, default 5
|
||||
:param reverse: if `True`, `pred['score'] *= -1`
|
||||
:param rank: if **True**, calculate rank ic
|
||||
:param graph_names: graph names; default ['cumulative_return', 'pred_ic', 'pred_autocorr', 'pred_turnover']
|
||||
:param show_notebook: whether to display graphics in notebook, the default is `True`
|
||||
:param show_nature_day: whether to display the abscissa of non-trading day
|
||||
:return: if show_notebook is True, display in notebook; else return `plotly.graph_objs.Figure` list
|
||||
:param N: group number, default 5.
|
||||
:param reverse: if `True`, `pred['score'] *= -1`.
|
||||
:param rank: if **True**, calculate rank ic.
|
||||
:param graph_names: graph names; default ['cumulative_return', 'pred_ic', 'pred_autocorr', 'pred_turnover'].
|
||||
:param show_notebook: whether to display graphics in notebook, the default is `True`.
|
||||
:param show_nature_day: whether to display the abscissa of non-trading day.
|
||||
:return: if show_notebook is True, display in notebook; else return `plotly.graph_objs.Figure` list.
|
||||
"""
|
||||
figure_list = []
|
||||
for graph_name in graph_names:
|
||||
|
||||
@@ -218,10 +218,10 @@ def cumulative_return_graph(
|
||||
|
||||
|
||||
Graph desc:
|
||||
- Axis X: Trading day
|
||||
- Axis X: Trading day.
|
||||
- Axis Y:
|
||||
- Above axis Y: `(((Ref($close, -1)/$close - 1) * weight).sum() / weight.sum()).cumsum()`
|
||||
- Below axis Y: Daily weight sum
|
||||
- Above axis Y: `(((Ref($close, -1)/$close - 1) * weight).sum() / weight.sum()).cumsum()`.
|
||||
- Below axis Y: Daily weight sum.
|
||||
- In the **sell** graph, `y < 0` stands for profit; in other cases, `y > 0` stands for profit.
|
||||
- In the **buy_minus_sell** graph, the **y** value of the **weight** graph at the bottom is `buy_weight + sell_weight`.
|
||||
- In each graph, the **red line** in the histogram on the right represents the average.
|
||||
|
||||
@@ -97,9 +97,9 @@ def rank_label_graph(
|
||||
qcr.rank_label_graph(positions, features_df, pred_df_dates.min(), pred_df_dates.max())
|
||||
|
||||
|
||||
:param position: position data; **qlib.contrib.backtest.backtest.backtest** result
|
||||
:param position: position data; **qlib.contrib.backtest.backtest.backtest** result.
|
||||
:param label_data: **D.features** result; index is **pd.MultiIndex**, index name is **[instrument, datetime]**; columns names is **[label]**.
|
||||
**The label T is the change from T to T+1**, it is recommended to use ``close``, example: `D.features(D.instruments('csi500'), ['Ref($close, -1)/$close-1'])`
|
||||
**The label T is the change from T to T+1**, it is recommended to use ``close``, example: `D.features(D.instruments('csi500'), ['Ref($close, -1)/$close-1'])`.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
@@ -115,7 +115,7 @@ def rank_label_graph(
|
||||
|
||||
:param start_date: start date
|
||||
:param end_date: end_date
|
||||
:param show_notebook: **True** or **False**. If True, show graph in notebook, else return figures
|
||||
:param show_notebook: **True** or **False**. If True, show graph in notebook, else return figures.
|
||||
:return:
|
||||
"""
|
||||
position = copy.deepcopy(position)
|
||||
|
||||
@@ -186,7 +186,7 @@ def report_graph(report_df: pd.DataFrame, show_notebook: bool = True) -> [list,
|
||||
|
||||
qcr.report_graph(report_normal_df)
|
||||
|
||||
:param report_df: **df.index.name** must be **date**, **df.columns** must contain **return**, **turnover**, **cost**, **bench**
|
||||
:param report_df: **df.index.name** must be **date**, **df.columns** must contain **return**, **turnover**, **cost**, **bench**.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
@@ -200,8 +200,8 @@ def report_graph(report_df: pd.DataFrame, show_notebook: bool = True) -> [list,
|
||||
2017-01-10 -0.000416 0.000440 -0.003350 0.208396
|
||||
|
||||
|
||||
:param show_notebook: whether to display graphics in notebook, the default is **True**
|
||||
:return: if show_notebook is True, display in notebook; else return **plotly.graph_objs.Figure** list
|
||||
:param show_notebook: whether to display graphics in notebook, the default is **True**.
|
||||
:return: if show_notebook is True, display in notebook; else return **plotly.graph_objs.Figure** list.
|
||||
"""
|
||||
report_df = report_df.copy()
|
||||
fig_list = _report_figure(report_df)
|
||||
|
||||
@@ -218,7 +218,7 @@ def risk_analysis_graph(
|
||||
max_drawdown -0.088263
|
||||
|
||||
|
||||
:param report_normal_df: **df.index.name** must be **date**, df.columns must contain **return**, **turnover**, **cost**, **bench**
|
||||
:param report_normal_df: **df.index.name** must be **date**, df.columns must contain **return**, **turnover**, **cost**, **bench**.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
@@ -232,7 +232,7 @@ def risk_analysis_graph(
|
||||
2017-01-10 -0.000416 0.000440 -0.003350 0.208396
|
||||
|
||||
|
||||
:param report_long_short_df: **df.index.name** must be **date**, df.columns contain **long**, **short**, **long_short**
|
||||
:param report_long_short_df: **df.index.name** must be **date**, df.columns contain **long**, **short**, **long_short**.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
@@ -246,7 +246,7 @@ def risk_analysis_graph(
|
||||
2017-01-10 0.000824 -0.001944 -0.001120
|
||||
|
||||
|
||||
:param show_notebook: Whether to display graphics in a notebook, default **True**
|
||||
:param show_notebook: Whether to display graphics in a notebook, default **True**.
|
||||
If True, show graph in notebook
|
||||
If False, return graph figure
|
||||
:return:
|
||||
|
||||
@@ -36,7 +36,7 @@ def score_ic_graph(pred_label: pd.DataFrame, show_notebook: bool = True) -> [lis
|
||||
analysis_position.score_ic_graph(pred_label)
|
||||
|
||||
|
||||
:param pred_label: index is **pd.MultiIndex**, index name is **[instrument, datetime]**; columns names is **[score, label]**
|
||||
:param pred_label: index is **pd.MultiIndex**, index name is **[instrument, datetime]**; columns names is **[score, label]**.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
@@ -49,8 +49,8 @@ def score_ic_graph(pred_label: pd.DataFrame, show_notebook: bool = True) -> [lis
|
||||
2017-12-15 -0.102778 -0.102778
|
||||
|
||||
|
||||
:param show_notebook: whether to display graphics in notebook, the default is **True**
|
||||
:return: if show_notebook is True, display in notebook; else return **plotly.graph_objs.Figure** list
|
||||
:param show_notebook: whether to display graphics in notebook, the default is **True**.
|
||||
:return: if show_notebook is True, display in notebook; else return **plotly.graph_objs.Figure** list.
|
||||
"""
|
||||
_ic_df = _get_score_ic(pred_label)
|
||||
# FIXME: support HIGH-FREQ
|
||||
|
||||
@@ -31,16 +31,16 @@ class BaseStrategy:
|
||||
Parameters
|
||||
-----------
|
||||
score_series : pd.Seires
|
||||
stock_id , score
|
||||
stock_id , score.
|
||||
current : Position()
|
||||
current state of position
|
||||
DO NOT directly change the state of current
|
||||
current state of position.
|
||||
DO NOT directly change the state of current.
|
||||
trade_exchange : Exchange()
|
||||
trade exchange
|
||||
trade exchange.
|
||||
pred_date : pd.Timestamp
|
||||
predict date
|
||||
predict date.
|
||||
trade_date : pd.Timestamp
|
||||
trade date
|
||||
trade date.
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -49,11 +49,11 @@ class BaseStrategy:
|
||||
Parameters
|
||||
-----------
|
||||
score_series : pd.Series
|
||||
stock_id , score
|
||||
stock_id , score.
|
||||
pred_date : pd.Timestamp
|
||||
oredict date
|
||||
oredict date.
|
||||
trade_date : pd.Timestamp
|
||||
trade date
|
||||
trade date.
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -67,7 +67,7 @@ class BaseStrategy:
|
||||
"""
|
||||
This method only be used in 'online' module, it will generate the *args to initial the strategy.
|
||||
:param
|
||||
mode : model used in 'online' module
|
||||
mode : model used in 'online' module.
|
||||
"""
|
||||
return {}
|
||||
|
||||
@@ -82,7 +82,7 @@ class StrategyWrapper:
|
||||
def __init__(self, inner_strategy):
|
||||
"""__init__
|
||||
|
||||
:param inner_strategy: set the inner strategy
|
||||
:param inner_strategy: set the inner strategy.
|
||||
"""
|
||||
self.inner_strategy = inner_strategy
|
||||
|
||||
@@ -99,9 +99,9 @@ class AdjustTimer:
|
||||
Responsible for timing of position adjusting
|
||||
|
||||
This is designed as multiple inheritance mechanism due to:
|
||||
- the is_adjust may need access to the internel state of a strategy
|
||||
- the is_adjust may need access to the internel state of a strategy.
|
||||
|
||||
- it can be reguard as a enhancement to the existing strategy
|
||||
- it can be reguard as a enhancement to the existing strategy.
|
||||
"""
|
||||
|
||||
# adjust position in each trade date
|
||||
@@ -146,12 +146,12 @@ class WeightStrategyBase(BaseStrategy, AdjustTimer):
|
||||
Parameters
|
||||
-----------
|
||||
score : pd.Series
|
||||
pred score for this trade date, index is stock_id, contain 'score' column
|
||||
pred score for this trade date, index is stock_id, contain 'score' column.
|
||||
current : Position()
|
||||
current position
|
||||
current position.
|
||||
trade_exchange : Exchange()
|
||||
trade_date : pd.Timestamp
|
||||
trade date
|
||||
trade date.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@@ -160,13 +160,13 @@ class WeightStrategyBase(BaseStrategy, AdjustTimer):
|
||||
Parameters
|
||||
-----------
|
||||
score_series : pd.Seires
|
||||
stock_id , score
|
||||
stock_id , score.
|
||||
current : Position()
|
||||
current of account
|
||||
current of account.
|
||||
trade_exchange : Exchange()
|
||||
exchange
|
||||
exchange.
|
||||
trade_date : pd.Timestamp
|
||||
date
|
||||
date.
|
||||
"""
|
||||
# judge if to adjust
|
||||
if not self.is_adjust(trade_date):
|
||||
@@ -206,26 +206,26 @@ class TopkDropoutStrategy(BaseStrategy, ListAdjustTimer):
|
||||
Parameters
|
||||
-----------
|
||||
topk : int
|
||||
The number of stocks in the portfolio
|
||||
the number of stocks in the portfolio.
|
||||
n_drop : int
|
||||
number of stocks to be replaced in each trading date
|
||||
number of stocks to be replaced in each trading date.
|
||||
method_sell : str
|
||||
dropout method_sell, random/bottom
|
||||
dropout method_sell, random/bottom.
|
||||
method_buy : str
|
||||
dropout method_buy, random/top
|
||||
dropout method_buy, random/top.
|
||||
risk_degree : float
|
||||
position percentage of total value
|
||||
position percentage of total value.
|
||||
thresh : int
|
||||
minimun holding days since last buy singal of the stock
|
||||
minimun holding days since last buy singal of the stock.
|
||||
hold_thresh : int
|
||||
minimum holding days
|
||||
before sell stock , will check current.get_stock_count(order.stock_id) >= self.thresh
|
||||
before sell stock , will check current.get_stock_count(order.stock_id) >= self.thresh.
|
||||
only_tradable : bool
|
||||
will the strategy only consider the tradable stock when buying and selling.
|
||||
if only_tradable:
|
||||
strategy will make buy sell decision without checking the tradable state of the stock
|
||||
strategy will make buy sell decision without checking the tradable state of the stock.
|
||||
else:
|
||||
strategy will make decision with the tradable state of the stock info and avoid buy and sell them
|
||||
strategy will make decision with the tradable state of the stock info and avoid buy and sell them.
|
||||
"""
|
||||
super(TopkDropoutStrategy, self).__init__()
|
||||
ListAdjustTimer.__init__(self, kwargs.get("adjust_dates", None))
|
||||
@@ -245,7 +245,7 @@ class TopkDropoutStrategy(BaseStrategy, ListAdjustTimer):
|
||||
def get_risk_degree(self, date):
|
||||
"""get_risk_degree
|
||||
Return the proportion of your total value you will used in investment.
|
||||
Dynamically risk_degree will result in Market timing
|
||||
Dynamically risk_degree will result in Market timing.
|
||||
"""
|
||||
# It will use 95% amoutn of your total value by default
|
||||
return self.risk_degree
|
||||
@@ -257,15 +257,15 @@ class TopkDropoutStrategy(BaseStrategy, ListAdjustTimer):
|
||||
Parameters
|
||||
-----------
|
||||
score_series : pd.Series
|
||||
stock_id , score
|
||||
stock_id , score.
|
||||
current : Position()
|
||||
current of account
|
||||
current of account.
|
||||
trade_exchange : Exchange()
|
||||
exchange
|
||||
exchange.
|
||||
pred_date : pd.Timestamp
|
||||
predict date
|
||||
predict date.
|
||||
trade_date : pd.Timestamp
|
||||
trade date
|
||||
trade date.
|
||||
"""
|
||||
if not self.is_adjust(trade_date):
|
||||
return []
|
||||
|
||||
Reference in New Issue
Block a user