mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-07 13:00:58 +08:00
fix bug
This commit is contained in:
committed by
you-n-g
parent
7ee4a207bc
commit
43a8f502ed
@@ -18,7 +18,7 @@ from ..config import C, REG_CN
|
||||
from ..utils.resam import resam_ts_data, ts_data_last
|
||||
from ..log import get_module_logger
|
||||
from .order import Order, OrderDir, OrderHelper
|
||||
from .high_performance_ds import PandasQuote, CN1min_NumpyQuote
|
||||
from .high_performance_ds import PandasQuote, CN1minNumpyQuote
|
||||
|
||||
|
||||
class Exchange:
|
||||
@@ -36,7 +36,7 @@ class Exchange:
|
||||
close_cost=0.0025,
|
||||
min_cost=5,
|
||||
extra_quote=None,
|
||||
quote_cls=CN1min_NumpyQuote,
|
||||
quote_cls=CN1minNumpyQuote,
|
||||
**kwargs,
|
||||
):
|
||||
"""__init__
|
||||
@@ -327,20 +327,20 @@ class Exchange:
|
||||
|
||||
"""
|
||||
if direction is None:
|
||||
buy_limit = self.quote.get_data(stock_id, start_time, end_time, fields="limit_buy", method="all")
|
||||
sell_limit = self.quote.get_data(stock_id, start_time, end_time, fields="limit_sell", method="all")
|
||||
buy_limit = self.quote.get_data(stock_id, start_time, end_time, field="limit_buy", method="all")
|
||||
sell_limit = self.quote.get_data(stock_id, start_time, end_time, field="limit_sell", method="all")
|
||||
return buy_limit or sell_limit
|
||||
elif direction == Order.BUY:
|
||||
return self.quote.get_data(stock_id, start_time, end_time, fields="limit_buy", method="all")
|
||||
return self.quote.get_data(stock_id, start_time, end_time, field="limit_buy", method="all")
|
||||
elif direction == Order.SELL:
|
||||
return self.quote.get_data(stock_id, start_time, end_time, fields="limit_sell", method="all")
|
||||
return self.quote.get_data(stock_id, start_time, end_time, field="limit_sell", method="all")
|
||||
else:
|
||||
raise ValueError(f"direction {direction} is not supported!")
|
||||
|
||||
def check_stock_suspended(self, stock_id, start_time, end_time):
|
||||
# is suspended
|
||||
if stock_id in self.quote.get_all_stock():
|
||||
return self.quote.get_data(stock_id, start_time, end_time) is None
|
||||
return self.quote.get_data(stock_id, start_time, end_time, "$close") is None
|
||||
else:
|
||||
return True
|
||||
|
||||
@@ -411,10 +411,10 @@ class Exchange:
|
||||
return self.quote.get_data(stock_id, start_time, end_time, method=method)
|
||||
|
||||
def get_close(self, stock_id, start_time, end_time, method=ts_data_last):
|
||||
return self.quote.get_data(stock_id, start_time, end_time, fields="$close", method=method)
|
||||
return self.quote.get_data(stock_id, start_time, end_time, field="$close", method=method)
|
||||
|
||||
def get_volume(self, stock_id, start_time, end_time, method="sum"):
|
||||
return self.quote.get_data(stock_id, start_time, end_time, fields="$volume", method=method)
|
||||
return self.quote.get_data(stock_id, start_time, end_time, field="$volume", method=method)
|
||||
|
||||
def get_deal_price(self, stock_id, start_time, end_time, direction: OrderDir, method=ts_data_last):
|
||||
if direction == OrderDir.SELL:
|
||||
@@ -423,7 +423,7 @@ class Exchange:
|
||||
pstr = self.buy_price
|
||||
else:
|
||||
raise NotImplementedError(f"This type of input is not supported")
|
||||
deal_price = self.quote.get_data(stock_id, start_time, end_time, fields=pstr, method=method)
|
||||
deal_price = self.quote.get_data(stock_id, start_time, end_time, field=pstr, method=method)
|
||||
if method is not None and (np.isclose(deal_price, 0.0) or np.isnan(deal_price)):
|
||||
self.logger.warning(f"(stock_id:{stock_id}, trade_time:{(start_time, end_time)}, {pstr}): {deal_price}!!!")
|
||||
self.logger.warning(f"setting deal_price to close price")
|
||||
@@ -441,7 +441,7 @@ class Exchange:
|
||||
assert start_time is not None and end_time is not None, "the time range must be given"
|
||||
if stock_id not in self.quote.get_all_stock():
|
||||
return None
|
||||
return self.quote.get_data(stock_id, start_time, end_time, fields="$factor", method=ts_data_last)
|
||||
return self.quote.get_data(stock_id, start_time, end_time, field="$factor", method=ts_data_last)
|
||||
|
||||
def generate_amount_position_from_weight_position(
|
||||
self, weight_position, cash, start_time, end_time, direction=OrderDir.BUY
|
||||
@@ -684,7 +684,7 @@ class Exchange:
|
||||
order.stock_id,
|
||||
order.start_time,
|
||||
order.end_time,
|
||||
fields=limit[1],
|
||||
field=limit[1],
|
||||
method="sum",
|
||||
)
|
||||
vol_limit_num.append(limit_value)
|
||||
@@ -693,7 +693,7 @@ class Exchange:
|
||||
order.stock_id,
|
||||
order.start_time,
|
||||
order.end_time,
|
||||
fields=limit[1],
|
||||
field=limit[1],
|
||||
method=ts_data_last,
|
||||
)
|
||||
vol_limit_num.append(limit_value - dealt_order_amount[order.stock_id])
|
||||
|
||||
@@ -2,21 +2,19 @@
|
||||
# Licensed under the MIT License.
|
||||
|
||||
|
||||
from builtins import ValueError, isinstance
|
||||
from functools import lru_cache
|
||||
import logging
|
||||
from typing import List, Text, Union, Callable, Iterable, Dict
|
||||
from collections import OrderedDict
|
||||
|
||||
import inspect
|
||||
import bisect
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
from ..utils.index_data import IndexData
|
||||
from ..utils.index_data import IndexData, SingleData
|
||||
from ..utils.resam import resam_ts_data, ts_data_last
|
||||
from ..log import get_module_logger
|
||||
from ..utils.time import if_single_data
|
||||
from ..utils.time import is_single_value
|
||||
|
||||
|
||||
class BaseQuote:
|
||||
@@ -39,10 +37,10 @@ class BaseQuote:
|
||||
stock_id: str,
|
||||
start_time: Union[pd.Timestamp, str],
|
||||
end_time: Union[pd.Timestamp, str],
|
||||
fields: Union[str, None] = None,
|
||||
field: Union[str],
|
||||
method: Union[str, Callable, None] = None,
|
||||
) -> Union[None, Union[int, float, bool], "IndexData"]:
|
||||
"""get the specific fields of stock data during start time and end_time,
|
||||
) -> Union[None, int, float, bool, "IndexData"]:
|
||||
"""get the specific field of stock data during start time and end_time,
|
||||
and apply method to the data.
|
||||
|
||||
Example:
|
||||
@@ -63,22 +61,13 @@ class BaseQuote:
|
||||
|
||||
this function is used for three case:
|
||||
|
||||
1. Both fields and method are not None. It returns int/float/bool.
|
||||
print(get_data(stock_id="SH600000", start_time="2010-01-04", end_time="2010-01-06", fields="$close", method="last"))
|
||||
1. method is not None. It returns int/float/bool.
|
||||
print(get_data(stock_id="SH600000", start_time="2010-01-04", end_time="2010-01-06", field="$close", method="last"))
|
||||
|
||||
85.713585
|
||||
|
||||
2. Both fields and method are None. It returns np.ndarray.
|
||||
print(get_data(stock_id="SH600000", start_time="2010-01-04", end_time="2010-01-06", fields=None, method=None))
|
||||
|
||||
[
|
||||
[86.778313, 16162960.0],
|
||||
[87.433578, 28117442.0],
|
||||
[85.713585, 23632884.0],
|
||||
]
|
||||
|
||||
3. fields is not None, and method is None. It returns IndexData.
|
||||
print(get_data(stock_id="SH600000", start_time="2010-01-04", end_time="2010-01-06", fields="$close", method=None))
|
||||
2. method is None. It returns IndexData.
|
||||
print(get_data(stock_id="SH600000", start_time="2010-01-04", end_time="2010-01-06", field="$close", method=None))
|
||||
|
||||
IndexData([86.778313, 87.433578, 85.713585], [2010-01-04, 2010-01-05, 2010-01-06])
|
||||
|
||||
@@ -89,7 +78,7 @@ class BaseQuote:
|
||||
closed start time for backtest
|
||||
end_time : Union[pd.Timestamp, str]
|
||||
closed end time for backtest
|
||||
fields : Union[str, None]
|
||||
field : str
|
||||
the columns of data to fetch
|
||||
method : Union[str, Callable, None]
|
||||
the method apply to data.
|
||||
@@ -97,7 +86,8 @@ class BaseQuote:
|
||||
|
||||
Return
|
||||
----------
|
||||
Union[None, Union[int, float, bool], IndexData]
|
||||
Union[None, int, float, bool, IndexData]
|
||||
None means there is no stock data from data source.
|
||||
please refer to Example as following.
|
||||
"""
|
||||
|
||||
@@ -115,32 +105,21 @@ class PandasQuote(BaseQuote):
|
||||
def get_all_stock(self):
|
||||
return self.data.keys()
|
||||
|
||||
def get_data(self, stock_id, start_time, end_time, fields=None, method=None):
|
||||
if fields is None and method is not None:
|
||||
raise ValueError(f"method must be None when fields is None")
|
||||
|
||||
if fields is None:
|
||||
stock_data = resam_ts_data(self.data[stock_id], start_time, end_time, method=method)
|
||||
elif isinstance(fields, str):
|
||||
stock_data = resam_ts_data(self.data[stock_id][fields], start_time, end_time, method=method)
|
||||
else:
|
||||
raise ValueError(f"fields must be None, str")
|
||||
|
||||
def get_data(self, stock_id, start_time, end_time, field, method=None):
|
||||
stock_data = resam_ts_data(self.data[stock_id][field], start_time, end_time, method=method)
|
||||
if stock_data is None:
|
||||
return None
|
||||
elif isinstance(stock_data, (bool, np.bool_, int, float, np.signedinteger, np.floating)):
|
||||
elif isinstance(stock_data, (bool, np.bool_, int, float, np.number)):
|
||||
return stock_data
|
||||
elif isinstance(stock_data, pd.Series):
|
||||
return IndexData.Series(stock_data)
|
||||
elif isinstance(stock_data, pd.DataFrame):
|
||||
return stock_data.values
|
||||
else:
|
||||
raise ValueError(f"stock data from resam_ts_data must be a number, pd.Series or pd.DataFrame")
|
||||
|
||||
|
||||
class CN1min_NumpyQuote(BaseQuote):
|
||||
class CN1minNumpyQuote(BaseQuote):
|
||||
def __init__(self, quote_df: pd.DataFrame):
|
||||
"""CN1min_NumpyQuote
|
||||
"""CN1minNumpyQuote
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@@ -153,48 +132,37 @@ class CN1min_NumpyQuote(BaseQuote):
|
||||
for stock_id, stock_val in quote_df.groupby(level="instrument"):
|
||||
quote_dict[stock_id] = IndexData.DataFrame(stock_val.droplevel(level="instrument"))
|
||||
self.data = quote_dict
|
||||
self.freq = np.timedelta64(1, "m")
|
||||
self.freq = pd.Timedelta(minutes=1)
|
||||
|
||||
def get_all_stock(self):
|
||||
return self.data.keys()
|
||||
|
||||
@lru_cache(maxsize=512)
|
||||
def get_data(self, stock_id, start_time, end_time, fields=None, method=None):
|
||||
if fields is None and method is not None:
|
||||
raise ValueError(f"method must be None when fields is None")
|
||||
|
||||
def get_data(self, stock_id, start_time, end_time, field, method=None):
|
||||
# check stock id
|
||||
if stock_id not in self.get_all_stock():
|
||||
return None
|
||||
|
||||
# single data
|
||||
# If it don't consider the classification of single data, it will consume a lot of time.
|
||||
if if_single_data(start_time, end_time, self.freq):
|
||||
if is_single_value(start_time, end_time, self.freq):
|
||||
now_index_map = self.data[stock_id].index_map
|
||||
now_columns_map = self.data[stock_id].columns_map
|
||||
if start_time not in now_index_map:
|
||||
return None
|
||||
if fields is None:
|
||||
return self.data[stock_id].values[now_index_map[start_time]]
|
||||
else:
|
||||
return self.data[stock_id].values[now_index_map[start_time], now_columns_map[fields]]
|
||||
return self.data[stock_id].values[now_index_map[start_time], now_columns_map[field]]
|
||||
|
||||
# multi data
|
||||
else:
|
||||
if fields is None and method is None:
|
||||
stock_data = self.data[stock_id].loc(start_time, end_time)
|
||||
if stock_data.empty:
|
||||
return None
|
||||
else:
|
||||
return stock_data.values
|
||||
elif fields is not None and method is None:
|
||||
stock_data = self.data[stock_id].loc(start_time, end_time, fields)
|
||||
if method is None:
|
||||
stock_data = self.data[stock_id].loc(start_time, end_time, field)
|
||||
if stock_data.empty:
|
||||
return None
|
||||
else:
|
||||
return stock_data
|
||||
elif fields is not None and method is not None:
|
||||
stock_data = self.data[stock_id].loc(start_time, end_time, fields)
|
||||
else:
|
||||
stock_data = self.data[stock_id].loc(start_time, end_time, field)
|
||||
if stock_data.empty:
|
||||
return None
|
||||
elif len(stock_data) == 1:
|
||||
@@ -231,6 +199,20 @@ class BaseSingleMetric:
|
||||
"""
|
||||
|
||||
def __init__(self, metric: Union[dict, pd.Series]):
|
||||
"""Single data structure for each metric.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
metric : Union[dict, pd.Series]
|
||||
keys/index is stock_id, value is the metric value.
|
||||
for example:
|
||||
SH600068 NaN
|
||||
SH600079 1.0
|
||||
SH600266 NaN
|
||||
...
|
||||
SZ300692 NaN
|
||||
SZ300719 NaN,
|
||||
"""
|
||||
raise NotImplementedError(f"Please implement the `__init__` method")
|
||||
|
||||
def __add__(self, other: Union["BaseSingleMetric", int, float]) -> "BaseSingleMetric":
|
||||
@@ -277,7 +259,7 @@ class BaseSingleMetric:
|
||||
def abs(self) -> "BaseSingleMetric":
|
||||
raise NotImplementedError(f"Please implement the `abs` method")
|
||||
|
||||
def astype(self, type: type) -> "BaseSingleMetric":
|
||||
def astype(self, dtype: type) -> "BaseSingleMetric":
|
||||
raise NotImplementedError(f"Please implement the `astype` method")
|
||||
|
||||
@property
|
||||
@@ -316,7 +298,8 @@ class BaseOrderIndicator:
|
||||
to inherit the BaseSingleMetric.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.logger = get_module_logger("online operator")
|
||||
|
||||
def assign(self, col: str, metric: Union[dict, pd.Series]):
|
||||
@@ -358,8 +341,13 @@ class BaseOrderIndicator:
|
||||
BaseSingleMetric
|
||||
new metric.
|
||||
"""
|
||||
|
||||
raise NotImplementedError(f"Please implement the 'transfer' method")
|
||||
func_sig = inspect.signature(func).parameters.keys()
|
||||
func_kwargs = {sig: self.data[sig] for sig in func_sig}
|
||||
tmp_metric = func(**func_kwargs)
|
||||
if new_col is not None:
|
||||
self.data[new_col] = tmp_metric
|
||||
else:
|
||||
return tmp_metric
|
||||
|
||||
def get_metric_series(self, metric: str) -> pd.Series:
|
||||
"""return the single metric with pd.Series format.
|
||||
@@ -378,8 +366,8 @@ class BaseOrderIndicator:
|
||||
|
||||
raise NotImplementedError(f"Please implement the 'get_metric_series' method")
|
||||
|
||||
def get_index_data(self, metric) -> IndexData.Series:
|
||||
"""get one metric with the format of IndexData.Series
|
||||
def get_index_data(self, metric) -> SingleData:
|
||||
"""get one metric with the format of SingleData
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@@ -389,7 +377,7 @@ class BaseOrderIndicator:
|
||||
Return
|
||||
------
|
||||
IndexData.Series
|
||||
one metric with the format of IndexData.Series
|
||||
one metric with the format of SingleData
|
||||
"""
|
||||
|
||||
raise NotImplementedError(f"Please implement the 'get_index_data' method")
|
||||
@@ -431,6 +419,9 @@ class BaseOrderIndicator:
|
||||
|
||||
|
||||
class SingleMetric(BaseSingleMetric):
|
||||
def __init__(self, metric):
|
||||
self.metric = metric
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, (int, float)):
|
||||
return self.__class__(self.metric + other)
|
||||
@@ -502,7 +493,7 @@ class SingleMetric(BaseSingleMetric):
|
||||
class PandasSingleMetric(SingleMetric):
|
||||
"""Each SingleMetric is based on pd.Series."""
|
||||
|
||||
def __init__(self, metric: Union[dict, pd.Series]):
|
||||
def __init__(self, metric: Union[dict, pd.Series] = {}):
|
||||
if isinstance(metric, dict):
|
||||
self.metric = pd.Series(metric)
|
||||
elif isinstance(metric, pd.Series):
|
||||
@@ -522,13 +513,17 @@ class PandasSingleMetric(SingleMetric):
|
||||
def abs(self):
|
||||
return self.__class__(self.metric.abs())
|
||||
|
||||
def astype(self, type):
|
||||
return self.__class__(self.metric.astype(type))
|
||||
def astype(self, dtype):
|
||||
return self.__class__(self.metric.astype(dtype))
|
||||
|
||||
@property
|
||||
def empty(self):
|
||||
return self.metric.empty
|
||||
|
||||
@property
|
||||
def index(self):
|
||||
return list(self.metric.index)
|
||||
|
||||
def add(self, other, fill_value=None):
|
||||
return self.__class__(self.metric.add(other.metric, fill_value=fill_value))
|
||||
|
||||
@@ -538,6 +533,9 @@ class PandasSingleMetric(SingleMetric):
|
||||
def apply(self, func: Callable):
|
||||
return self.__class__(self.metric.apply(func))
|
||||
|
||||
def reindex(self, index, fill_value):
|
||||
return self.__class__(self.metric.reindex(index, fill_value=fill_value))
|
||||
|
||||
|
||||
class PandasOrderIndicator(BaseOrderIndicator):
|
||||
"""
|
||||
@@ -552,15 +550,6 @@ class PandasOrderIndicator(BaseOrderIndicator):
|
||||
def assign(self, col: str, metric: Union[dict, pd.Series]):
|
||||
self.data[col] = PandasSingleMetric(metric)
|
||||
|
||||
def transfer(self, func: Callable, new_col: str = None) -> Union[None, PandasSingleMetric]:
|
||||
func_sig = inspect.signature(func).parameters.keys()
|
||||
func_kwargs = {sig: self.data[sig] for sig in func_sig}
|
||||
tmp_metric = func(**func_kwargs)
|
||||
if new_col is not None:
|
||||
self.data[new_col] = tmp_metric
|
||||
else:
|
||||
return tmp_metric
|
||||
|
||||
def get_index_data(self, metric):
|
||||
if metric in self.data:
|
||||
return IndexData.Series(self.data[metric].metric)
|
||||
@@ -577,7 +566,7 @@ class PandasOrderIndicator(BaseOrderIndicator):
|
||||
return {k: v.metric for k, v in self.data.items()}
|
||||
|
||||
@staticmethod
|
||||
def sum_all_indicators(order_indicator, indicators: list, metrics: Union[str, List[str]], fill_value=None):
|
||||
def sum_all_indicators(order_indicator, indicators: list, metrics: Union[str, List[str]], fill_value=0):
|
||||
if isinstance(metrics, str):
|
||||
metrics = [metrics]
|
||||
for metric in metrics:
|
||||
@@ -589,26 +578,17 @@ class PandasOrderIndicator(BaseOrderIndicator):
|
||||
|
||||
class NumpyOrderIndicator(BaseOrderIndicator):
|
||||
"""
|
||||
The data structure is OrderedDict(str: IndexData.Series).
|
||||
The data structure is OrderedDict(str: SingleData).
|
||||
Each IndexData.Series is one metric.
|
||||
Str is the name of metric.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.data: Dict[str, IndexData.Series] = OrderedDict()
|
||||
self.data: Dict[str, SingleData] = OrderedDict()
|
||||
|
||||
def assign(self, col: str, metric: dict):
|
||||
self.data[col] = IndexData.Series(metric)
|
||||
|
||||
def transfer(self, func: Callable, new_col: str = None) -> Union[None, IndexData.Series]:
|
||||
func_sig = inspect.signature(func).parameters.keys()
|
||||
func_kwargs = {sig: self.data[sig] for sig in func_sig}
|
||||
tmp_metric = func(**func_kwargs)
|
||||
if new_col is not None:
|
||||
self.data[new_col] = tmp_metric
|
||||
else:
|
||||
return tmp_metric
|
||||
|
||||
def get_index_data(self, metric):
|
||||
if metric in self.data:
|
||||
return self.data[metric]
|
||||
@@ -616,7 +596,7 @@ class NumpyOrderIndicator(BaseOrderIndicator):
|
||||
return IndexData.Series()
|
||||
|
||||
def get_metric_series(self, metric: str) -> Union[pd.Series]:
|
||||
return self.data[metric].to_pd_series()
|
||||
return self.data[metric].to_series()
|
||||
|
||||
def to_series(self) -> Dict[str, pd.Series]:
|
||||
tmp_metric_dict = {}
|
||||
|
||||
@@ -109,7 +109,7 @@ class Order:
|
||||
return self.direction * 2 - 1
|
||||
|
||||
@staticmethod
|
||||
def parse_dir(direction: Union[str, int, np.integer, OrderDir, np.ndarray]) -> OrderDir:
|
||||
def parse_dir(direction: Union[str, int, np.integer, OrderDir, np.ndarray]) -> Union[OrderDir, np.ndarray]:
|
||||
if isinstance(direction, OrderDir):
|
||||
return direction
|
||||
elif isinstance(direction, (int, float, np.integer, np.floating)):
|
||||
|
||||
@@ -4,15 +4,14 @@
|
||||
|
||||
from collections import OrderedDict
|
||||
import pathlib
|
||||
from typing import Dict, List, Tuple
|
||||
from typing import Dict, List, Tuple, Union
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from qlib.backtest.exchange import Exchange
|
||||
from qlib.backtest.order import BaseTradeDecision, Order, OrderDir
|
||||
|
||||
from .high_performance_ds import PandasOrderIndicator, NumpyOrderIndicator
|
||||
from .high_performance_ds import PandasOrderIndicator, NumpyOrderIndicator, SingleMetric
|
||||
from ..utils.index_data import IndexData, SingleData
|
||||
from ..tests.config import CSI300_BENCH
|
||||
from ..utils.resam import get_higher_eq_freq_feature, resam_ts_data
|
||||
@@ -305,8 +304,9 @@ class Indicator:
|
||||
|
||||
def _update_order_fulfill_rate(self):
|
||||
def func(deal_amount, amount):
|
||||
# deal_amount is np.NaN when there is no inner decision. So full fill rate is 0.
|
||||
tmp_deal_amount = deal_amount.replace({np.NaN: 0})
|
||||
# deal_amount is np.NaN or None when there is no inner decision. So full fill rate is 0.
|
||||
tmp_deal_amount = deal_amount.reindex(amount.index, 0)
|
||||
tmp_deal_amount = tmp_deal_amount.replace({np.NaN: 0})
|
||||
return tmp_deal_amount / amount
|
||||
|
||||
self.order_indicator.transfer(func, "ffr")
|
||||
@@ -385,7 +385,7 @@ class Indicator:
|
||||
if price_s is None:
|
||||
return None, None
|
||||
|
||||
if isinstance(price_s, (int, float, np.signedinteger, np.floating)):
|
||||
if isinstance(price_s, (int, float, np.number)):
|
||||
price_s = IndexData.Series(price_s, [trade_start_time])
|
||||
elif isinstance(price_s, SingleData):
|
||||
pass
|
||||
@@ -400,7 +400,7 @@ class Indicator:
|
||||
|
||||
if agg == "vwap":
|
||||
volume_s = trade_exchange.get_volume(inst, trade_start_time, trade_end_time, method=None)
|
||||
if isinstance(volume_s, (int, float, np.floating)):
|
||||
if isinstance(volume_s, (int, float, np.number)):
|
||||
volume_s = IndexData.Series(volume_s, [trade_start_time])
|
||||
volume_s = volume_s.reindex(price_s.index)
|
||||
elif agg == "twap":
|
||||
@@ -414,7 +414,7 @@ class Indicator:
|
||||
|
||||
def _agg_base_price(
|
||||
self,
|
||||
inner_order_indicators: List[Dict[str, pd.Series]],
|
||||
inner_order_indicators: List[Dict[str, Union[SingleMetric, SingleData]]],
|
||||
decision_list: List[Tuple[BaseTradeDecision, pd.Timestamp, pd.Timestamp]],
|
||||
trade_exchange: Exchange,
|
||||
pa_config: dict = {},
|
||||
|
||||
@@ -35,7 +35,7 @@ class IndexData:
|
||||
return MultiData(data, index, columns)
|
||||
|
||||
@staticmethod
|
||||
def concat(data_list, axis=0):
|
||||
def concat(data_list: Union["SingleData"], axis=0) -> "MultiData":
|
||||
"""concat all SingleData by index.
|
||||
TODO: now just for SingleData.
|
||||
|
||||
@@ -50,7 +50,7 @@ class IndexData:
|
||||
the MultiData with ndim == 2
|
||||
"""
|
||||
if axis == 0:
|
||||
raise NotImplementedError(f"please implement this fuc when axis == 0")
|
||||
raise NotImplementedError(f"please implement this func when axis == 0")
|
||||
elif axis == 1:
|
||||
# get all index and row
|
||||
all_index = set()
|
||||
@@ -90,7 +90,7 @@ class BaseData:
|
||||
raise NotImplementedError(f"please implement _align_index func")
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, (int, float, np.floating)):
|
||||
if isinstance(other, (int, float, np.number)):
|
||||
return self.__class__(self.data + other, *self.index_columns)
|
||||
elif isinstance(other, self.__class__):
|
||||
tmp_data1, tmp_data2 = self._align_index(other)
|
||||
@@ -99,7 +99,7 @@ class BaseData:
|
||||
return NotImplemented
|
||||
|
||||
def __sub__(self, other):
|
||||
if isinstance(other, (int, float, np.floating)):
|
||||
if isinstance(other, (int, float, np.number)):
|
||||
return self.__class__(self.data - other, *self.index_columns)
|
||||
elif isinstance(other, self.__class__):
|
||||
tmp_data1, tmp_data2 = self._align_index(other)
|
||||
@@ -108,7 +108,7 @@ class BaseData:
|
||||
return NotImplemented
|
||||
|
||||
def __rsub__(self, other):
|
||||
if isinstance(other, (int, float, np.floating)):
|
||||
if isinstance(other, (int, float, np.number)):
|
||||
return self.__class__(other - self.data, *self.index_columns)
|
||||
elif isinstance(other, self.__class__):
|
||||
tmp_data1, tmp_data2 = self._align_index(other)
|
||||
@@ -117,7 +117,7 @@ class BaseData:
|
||||
return NotImplemented
|
||||
|
||||
def __mul__(self, other):
|
||||
if isinstance(other, (int, float, np.floating)):
|
||||
if isinstance(other, (int, float, np.number)):
|
||||
return self.__class__(self.data * other, *self.index_columns)
|
||||
elif isinstance(other, self.__class__):
|
||||
tmp_data1, tmp_data2 = self._align_index(other)
|
||||
@@ -126,7 +126,7 @@ class BaseData:
|
||||
return NotImplemented
|
||||
|
||||
def __truediv__(self, other):
|
||||
if isinstance(other, (int, float, np.floating)):
|
||||
if isinstance(other, (int, float, np.number)):
|
||||
return self.__class__(self.data / other, *self.index_columns)
|
||||
elif isinstance(other, self.__class__):
|
||||
tmp_data1, tmp_data2 = self._align_index(other)
|
||||
@@ -135,7 +135,7 @@ class BaseData:
|
||||
return NotImplemented
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, (int, float, np.floating)):
|
||||
if isinstance(other, (int, float, np.number)):
|
||||
return self.__class__(self.data == other, *self.index_columns)
|
||||
elif isinstance(other, self.__class__):
|
||||
tmp_data1, tmp_data2 = self._align_index(other)
|
||||
@@ -144,7 +144,7 @@ class BaseData:
|
||||
return NotImplemented
|
||||
|
||||
def __gt__(self, other):
|
||||
if isinstance(other, (int, float, np.floating)):
|
||||
if isinstance(other, (int, float, np.number)):
|
||||
return self.__class__(self.data > other, *self.index_columns)
|
||||
elif isinstance(other, self.__class__):
|
||||
tmp_data1, tmp_data2 = self._align_index(other)
|
||||
@@ -153,7 +153,7 @@ class BaseData:
|
||||
return NotImplemented
|
||||
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, (int, float, np.floating)):
|
||||
if isinstance(other, (int, float, np.number)):
|
||||
return self.__class__(self.data < other, *self.index_columns)
|
||||
elif isinstance(other, self.__class__):
|
||||
tmp_data1, tmp_data2 = self._align_index(other)
|
||||
@@ -169,9 +169,9 @@ class BaseData:
|
||||
tmp_data = np.absolute(self.data)
|
||||
return self.__class__(tmp_data, *self.index_columns)
|
||||
|
||||
def astype(self, type):
|
||||
def astype(self, dtype):
|
||||
"""change the type of data."""
|
||||
tmp_data = self.data.astype(type)
|
||||
tmp_data = self.data.astype(dtype)
|
||||
return self.__class__(tmp_data, *self.index_columns)
|
||||
|
||||
def replace(self, to_replace: dict):
|
||||
@@ -234,7 +234,7 @@ class BaseData:
|
||||
|
||||
|
||||
class SingleData(BaseData):
|
||||
def __init__(self, data: Union[int, float, np.floating, list, np.ndarray] = [], index: Union[list, pd.Index] = []):
|
||||
def __init__(self, data: Union[int, float, np.number, list] = [], index: Union[list, pd.Index] = []):
|
||||
"""A data structure of index and numpy data.
|
||||
It's used to replace pd.Series due to high-speed.
|
||||
|
||||
@@ -301,6 +301,8 @@ class SingleData(BaseData):
|
||||
SingleData
|
||||
reindex data
|
||||
"""
|
||||
if self.index == index:
|
||||
return self
|
||||
tmp_data = np.full(len(index), fill_value, dtype=np.float64)
|
||||
for index_id, index_item in enumerate(index):
|
||||
if index_item in self.index:
|
||||
@@ -323,17 +325,7 @@ class SingleData(BaseData):
|
||||
"""
|
||||
return dict(zip(self.index, self.data.tolist()))
|
||||
|
||||
def to_frame(self):
|
||||
"""convert SingleData to MultiData.
|
||||
|
||||
Returns
|
||||
-------
|
||||
MultiData
|
||||
data with the MultiData format.
|
||||
"""
|
||||
return MultiData(self.data[:, np.newaxis], self.index)
|
||||
|
||||
def to_pd_series(self):
|
||||
def to_series(self):
|
||||
return pd.Series(self.data, index=self.index)
|
||||
|
||||
def __getitem__(self, index: Union["SingleData", int, str]):
|
||||
|
||||
@@ -38,8 +38,8 @@ def get_min_cal(shift: int = 0) -> List[time]:
|
||||
return cal
|
||||
|
||||
|
||||
def if_single_data(start_time, end_time, freq):
|
||||
"""Is there only one piece of data to obtain.
|
||||
def is_single_value(start_time, end_time, freq):
|
||||
"""Is there only one piece of data for cn stock market.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
Reference in New Issue
Block a user