Skip to content

Commit

Permalink
V0.9.63 更新一批代码 (#222)
Browse files Browse the repository at this point in the history
* 0.9.63 start coding

* 0.9.63 优化 get_symbols

* 0.9.63 fix cal_symbols_factor

* remove

* 0.9.63 fix import

* 0.9.63 fix import

* 0.9.63 yearly_days 最大值限制在365

* 0.9.63 update

* 0.9.63 删除 deprecated 函数

* 0.9.63 支持自定义数据库名称

* 0.9.63 删除不必要的类

* 0.9.63 使用 rs_czsc 替换几个函数

* 0.9.63 github actions 不再支持3.8

* 0.9.63 新增 rust 版本的简单测试

* 0.9.63 新增 rust 版本的简单测试
  • Loading branch information
zengbin93 authored Feb 19, 2025
1 parent 8daa121 commit ddf55c1
Show file tree
Hide file tree
Showing 25 changed files with 517 additions and 2,209 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: Python package

on:
push:
branches: [ master, 'V0.9.62' ]
branches: [ master, 'V0.9.63' ]
pull_request:
branches: [ master ]

Expand All @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9, '3.10', '3.11', '3.12']
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']

steps:
- uses: actions/checkout@v2
Expand Down
48 changes: 27 additions & 21 deletions czsc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,22 @@
email: [email protected]
create_dt: 2019/10/29 15:01
"""
from rs_czsc import (
daily_performance,
top_drawdowns,

# python版本:from czsc.traders.weight_backtest import WeightBacktest
WeightBacktest,
)

from czsc import envs
from czsc import fsa
from czsc import utils
from czsc import traders
from czsc import sensors
from czsc import aphorism
from czsc.traders import rwc
from czsc.traders import cwc
from czsc.analyze import CZSC
from czsc.objects import Freq, Operate, Direction, Signal, Factor, Event, RawBar, NewBar, Position, ZS
from czsc.strategies import CzscStrategyBase, CzscJsonStrategy
Expand All @@ -25,27 +35,28 @@
PairsPerformance,
combine_holds_and_pairs,
combine_dates_and_pairs,
stock_holds_performance,
DummyBacktest,
SignalsParser,
get_signals_config,
get_signals_freqs,

WeightBacktest,
stoploss_by_direction,
get_ensemble_weight,
long_short_equity,

OpensOptimize,
ExitsOptimize,
)

from czsc.traders.rwc import (
RedisWeightsClient,
get_strategy_mates,
get_strategy_names,
get_heartbeat_time,
clear_strategy,
get_strategy_weights,
get_strategy_latest,

OpensOptimize,
ExitsOptimize,
)

from czsc.utils import (
timeout_decorator,
mac_address,
Expand Down Expand Up @@ -81,18 +92,13 @@
risk_free_returns,
resample_to_daily,

CrossSectionalPerformance,
cross_sectional_ranker,
cross_sectional_ic,
SignalAnalyzer,
SignalPerformance,
daily_performance,
# daily_performance,
rolling_daily_performance,
weekly_performance,
holds_performance,
net_value_stats,
subtract_fee,
top_drawdowns,
# top_drawdowns,
psi,

home_path,
Expand Down Expand Up @@ -138,7 +144,6 @@
show_correlation,
show_corr_graph,
show_sectional_ic,
show_factor_returns,
show_factor_layering,
show_symbol_factor_layering,
show_weight_backtest,
Expand Down Expand Up @@ -175,7 +180,7 @@
from czsc.utils.features import (
normalize_feature,
normalize_ts_feature,
feture_cross_layering,
feature_cross_layering,
find_most_similarity,
)

Expand Down Expand Up @@ -221,13 +226,16 @@
)


__version__ = "0.9.62"
__version__ = "0.9.63"
__author__ = "zengbin93"
__email__ = "[email protected]"
__date__ = "20241208"
__date__ = "20250101"


def welcome():
from czsc import aphorism, envs
from czsc.utils import get_dir_size, home_path

print(f"欢迎使用CZSC!当前版本标识为 {__version__}@{__date__}\n")
aphorism.print_one()

Expand All @@ -236,10 +244,8 @@ def welcome():
f"czsc_min_bi_len = {envs.get_min_bi_len()}; "
f"czsc_max_bi_num = {envs.get_max_bi_num()}; "
)


if envs.get_welcome():
welcome()
if get_dir_size(home_path) > pow(1024, 3):
print(f"{home_path} 目录缓存超过1GB,请适当清理。调用 czsc.empty_cache_path() 可以直接清空缓存")


if get_dir_size(home_path) > pow(1024, 3):
Expand Down
65 changes: 38 additions & 27 deletions czsc/eda.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import numpy as np
from typing import Callable
from tqdm import tqdm
from sklearn.linear_model import Ridge, LinearRegression, Lasso


def vwap(price: np.array, volume: np.array, **kwargs) -> float:
Expand Down Expand Up @@ -45,6 +44,7 @@ def remove_beta_effects(df, **kwargs):
:return: DataFrame
"""
from sklearn.linear_model import Ridge, LinearRegression, Lasso

linear_model = kwargs.get("linear_model", "ridge")
linear_model_params = kwargs.get("linear_model_params", {})
Expand Down Expand Up @@ -268,7 +268,7 @@ def cal_yearly_days(dts: list, **kwargs):

# 按年重采样并计算每年的交易日数量,取最大值
yearly_days = dts.resample('YE').size().max()
return yearly_days
return min(yearly_days, 365)


def cal_symbols_factor(dfk: pd.DataFrame, factor_function: Callable, **kwargs):
Expand All @@ -282,44 +282,55 @@ def cal_symbols_factor(dfk: pd.DataFrame, factor_function: Callable, **kwargs):
- factor_params: dict, 因子计算参数
- min_klines: int, 最小K线数据量,默认为 300
- price_type: str, 交易价格类型,默认为 close,可选值为 close 或 next_open
- strict: bool, 是否严格模式,默认为 True, 严格模式下,计算因子出错会抛出异常
:return: dff, pd.DataFrame, 计算后的因子数据
"""
logger = kwargs.get("logger", loguru.logger)
min_klines = kwargs.get("min_klines", 300)
factor_params = kwargs.get("factor_params", {})
price_type = kwargs.get("price_type", "close")
strict = kwargs.get("strict", True)

symbols = dfk["symbol"].unique().tolist()
factor_name = factor_function.__name__

def __one_symbol(symbol):
df = dfk[(dfk["symbol"] == symbol)].copy()
df = df.sort_values("dt", ascending=True).reset_index(drop=True)
if len(df) < min_klines:
logger.warning(f"{symbol} 数据量过小,跳过;仅有 {len(df)} 条数据,需要 {min_klines} 条数据")
return None

df = factor_function(df, **factor_params)
if price_type == 'next_open':
df["price"] = df["open"].shift(-1).fillna(df["close"])
elif price_type == 'close':
df["price"] = df["close"]
else:
raise ValueError("price_type 参数错误, 可选值为 close 或 next_open")

df["n1b"] = (df["price"].shift(-1) / df["price"] - 1).fillna(0)
factor = [x for x in df.columns if x.startswith("F#")][0]

# df[factor] = df[factor].replace([np.inf, -np.inf], np.nan).ffill().fillna(0)
# factor 中不能有 inf 和 -inf 值,也不能有 nan 值
assert df[factor].isna().sum() == 0, f"{symbol} {factor} 存在 nan 值"
assert df[factor].isin([np.inf, -np.inf]).sum() == 0, f"{symbol} {factor} 存在 inf 值"
assert df[factor].var() != 0 and not np.isnan(df[factor].var()), f"{symbol} {factor} var is 0 or nan"
return df

rows = []
for symbol in tqdm(symbols, desc=f"{factor_name} 因子计算"):
try:
df = dfk[(dfk["symbol"] == symbol)].copy()
df = df.sort_values("dt", ascending=True).reset_index(drop=True)
if len(df) < min_klines:
logger.warning(f"{symbol} 数据量过小,跳过;仅有 {len(df)} 条数据,需要 {min_klines} 条数据")
for _symbol in tqdm(symbols, desc=f"{factor_name} 因子计算"):
if strict:
dfx = __one_symbol(_symbol)
else:
try:
dfx = __one_symbol(_symbol)
except Exception as e:
logger.error(f"{factor_name} - {_symbol} - 计算因子出错:{e}")
continue

df = factor_function(df, **factor_params)
if price_type == 'next_open':
df["price"] = df["open"].shift(-1).fillna(df["close"])
elif price_type == 'close':
df["price"] = df["close"]
else:
raise ValueError("price_type 参数错误, 可选值为 close 或 next_open")

df["n1b"] = (df["price"].shift(-1) / df["price"] - 1).fillna(0)

factor = [x for x in df.columns if x.startswith("F#")][0]
df[factor] = df[factor].replace([np.inf, -np.inf], np.nan).ffill().fillna(0)
if df[factor].var() == 0 or np.isnan(df[factor].var()):
logger.warning(f"{symbol} {factor} var is 0 or nan")
else:
rows.append(df.copy())
except Exception as e:
logger.error(f"{factor_name} - {symbol} - 计算因子出错:{e}")
rows.append(dfx)

dff = pd.concat(rows, ignore_index=True)
return dff
Expand Down
Loading

0 comments on commit ddf55c1

Please sign in to comment.