Skip to content

Commit

Permalink
V0.9.26 更新一批代码 (#161)
Browse files Browse the repository at this point in the history
* 0.9.26 update

* 0.9.26 新增两个信号函数

* 0.9.26 update

* 0.9.26 新增按持仓权重进行回测的模块

* 0.9.26 update

* 0.9.26 update

* 0.9.26 update

* 0.9.26 update

* 0.9.26 更新一批信号函数

* 0.9.26 更新信号函数

* 0.9.26 update

* 0.9.26 新增信号函数

* 0.9.26 update
  • Loading branch information
zengbin93 authored Aug 11, 2023
1 parent c431de6 commit ffc7240
Show file tree
Hide file tree
Showing 27 changed files with 1,758 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .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.25 ]
branches: [ master, V0.9.26 ]
pull_request:
branches: [ master ]

Expand Down
11 changes: 7 additions & 4 deletions czsc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,27 @@
from czsc import aphorism
from czsc.analyze import CZSC
from czsc.objects import Freq, Operate, Direction, Signal, Factor, Event, RawBar, NewBar, Position
from czsc.utils.cache import home_path, get_dir_size, empty_cache_path

from czsc.traders import CzscTrader, CzscSignals, generate_czsc_signals, check_signals_acc, get_unique_signals
from czsc.traders import PairsPerformance, combine_holds_and_pairs, combine_dates_and_pairs, stock_holds_performance
from czsc.traders import DummyBacktest, SignalsParser, get_signals_by_conf, get_signals_config, get_signals_freqs
from czsc.traders import WeightBacktest, get_ensemble_weight
from czsc.sensors import holds_concepts_effect, CTAResearch, EventMatchSensor
from czsc.strategies import CzscStrategyBase, CzscJsonStrategy

from czsc.utils import KlineChart, BarGenerator, resample_bars, dill_dump, dill_load, read_json, save_json
from czsc.utils import get_sub_elements, get_py_namespace, freqs_sorted, x_round, import_by_name, create_grid_params
from czsc.utils import cal_trade_price, cross_sectional_ic, update_bbars, update_tbars, update_nbars
from czsc.utils import CrossSectionalPerformance
from czsc.sensors import holds_concepts_effect, CTAResearch, EventMatchSensor
from czsc.utils.signal_analyzer import SignalAnalyzer, SignalPerformance
from czsc.utils.stats import daily_performance, net_value_stats, subtract_fee
from czsc.utils.cache import home_path, get_dir_size, empty_cache_path


__version__ = "0.9.25"
__version__ = "0.9.26"
__author__ = "zengbin93"
__email__ = "[email protected]"
__date__ = "20230716"
__date__ = "20230726"


def welcome():
Expand Down
9 changes: 7 additions & 2 deletions czsc/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
from dataclasses import dataclass, field
from datetime import datetime
from loguru import logger
from typing import List, Callable, AnyStr, Dict, Optional
from deprecated import deprecated
from typing import List, Callable, Dict
from czsc.enum import Mark, Direction, Freq, Operate
from czsc.utils.corr import single_linear


@deprecated(version="1.0.0", reason="请使用 RawBar")
@dataclass
class Tick:
symbol: str
Expand Down Expand Up @@ -911,6 +913,7 @@ def pairs(self):

return pairs

@deprecated(version="1.0.0", reason="请使用 czsc.utils.stats.evaluate_pairs")
def evaluate_pairs(self, trade_dir: str = "多空") -> dict:
"""评估交易表现
Expand Down Expand Up @@ -1037,7 +1040,9 @@ def evaluate(self, trade_dir: str = "多空") -> dict:
:param trade_dir: 交易方向,可选值 ['多头', '空头', '多空']
:return: 交易表现
"""
p = self.evaluate_pairs(trade_dir)
from czsc.utils.stats import evaluate_pairs

p = evaluate_pairs(pd.DataFrame(self.pairs), trade_dir)
p.update(self.evaluate_holds(trade_dir))
return p

Expand Down
9 changes: 7 additions & 2 deletions czsc/sensors/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,13 @@ def report(self):


class FixedNumberSelector:
"""选择固定数量(等权)的交易品种"""

"""选择固定数量(等权)的交易品种
可优化项:
1. 传入 res_path, 将分析过程和分析结果保存下来
2. 支持传入大盘择时信号,例如:大盘择时信号为空头时,多头只平不开
"""

def __init__(self, dfs, k, d, **kwargs):
"""
Expand Down
9 changes: 9 additions & 0 deletions czsc/signals/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
vol_double_ma_V230214,
vol_ti_suo_V221216,
vol_gao_di_V221218,
vol_window_V230731,
vol_window_V230801,
)

from czsc.signals.bar import (
Expand Down Expand Up @@ -98,6 +100,9 @@
bar_shuang_fei_V230507,
bar_limit_down_V230525,
bar_eight_V230702,
bar_window_std_V230731,
bar_window_ps_V230731,
bar_window_ps_V230801,
)

from czsc.signals.jcc import (
Expand Down Expand Up @@ -184,13 +189,15 @@
tas_low_trend_V230627,
tas_atr_V230630,
tas_accelerate_V230531,
tas_angle_V230802,

tas_rumi_V230704,
tas_macd_dist_V230408,
tas_macd_dist_V230409,
tas_macd_dist_V230410,
cat_macd_V230518,
cat_macd_V230520,
tas_macd_bc_V230803,
)

from czsc.signals.pos import (
Expand All @@ -200,6 +207,8 @@
pos_bar_stop_V230524,
pos_fix_exit_V230624,
pos_profit_loss_V230624,
pos_status_V230808,
pos_holds_V230807,
)


Expand Down
164 changes: 164 additions & 0 deletions czsc/signals/bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -1468,3 +1468,167 @@ def bar_eight_V230702(c: CZSC, **kwargs) -> OrderedDict:
v1 = "转折平衡市"

return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)


def bar_window_std_V230731(c: CZSC, **kwargs) -> OrderedDict:
"""指定窗口内波动率的特征
参数模板:"{freq}_D{di}W{window}M{m}N{n}_窗口波动V230731"
**信号逻辑:**
滚动计算最近m根K线的波动率,分成n层,最大值为n,最小值为1;
最近window根K线的最大值为max_layer,最小值为min_layer。
以这两个值作为窗口内的波动率特征。
**信号列表:**
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N7_低波N6_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N6_低波N6_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N8_低波N6_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N9_低波N6_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N9_低波N9_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N9_低波N8_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N8_低波N8_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N8_低波N7_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N7_低波N7_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N7_低波N5_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N6_低波N5_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N5_低波N4_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N5_低波N3_任意_0')
- Signal('60分钟_D2W3M100N10_窗口波动V230731_高波N4_低波N3_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param w: 观察的窗口大小。
- :param m: 计算分位数所需取K线的数量。
- :param n: 分层的数量。
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
w = int(kwargs.get("w", 5))
m = int(kwargs.get("m", 100))
n = int(kwargs.get("n", 10))

# 更新STD20波动率缓存
cache_key = "STD20"
for i, bar in enumerate(c.bars_raw):
if cache_key in bar.cache:
continue
bar.cache[cache_key] = 0 if i < 5 else np.std([x.close for x in c.bars_raw[max(i-20, 0):i]])

freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}W{w}M{m}N{n}_窗口波动V230731".split('_')
v1 = "其他"

if len(c.bars_raw) < di + m + w:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

stds = [x.cache[cache_key] for x in get_sub_elements(c.bars_raw, di=di, n=m)]
layer = pd.qcut(stds, n, labels=False, duplicates='drop')
max_layer = max(layer[-w:]) + 1
min_layer = min(layer[-w:]) + 1

v1, v2 = f"高波N{max_layer}", f"低波N{min_layer}"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1, v2=v2)



def bar_window_ps_V230731(c: CZSC, **kwargs) -> OrderedDict:
"""指定窗口内支撑压力位分位数计算,贡献者:chenlei
参数模板:"{freq}_W{w}M{m}N{n}L{l}_支撑压力位V230731"
**信号逻辑:**
1. 计算最近 N 笔的最高价 NH 和最低价 NL,这个可以近似理解成价格的支撑和压力位
2. 计算并缓存最新K线的收盘价格 C 处于 NH、NL 之间的位置,计算方法为 P = (C - NL)/ (NH - NL)
3. 取最近 M 个 P 值序列,按分位数分层,分层数量为 L,分层的最大值为最近的压力,最小值为最近的支撑,当前值为最近的价格位置
**信号列表:**
- Signal('15分钟_W5M40N8L5_支撑压力位V230731_压力N5_支撑N5_当前N5_0')
- Signal('15分钟_W5M40N8L5_支撑压力位V230731_压力N5_支撑N4_当前N5_0')
- Signal('15分钟_W5M40N8L5_支撑压力位V230731_压力N5_支撑N4_当前N4_0')
- Signal('15分钟_W5M40N8L5_支撑压力位V230731_压力N5_支撑N3_当前N5_0')
- Signal('15分钟_W5M40N8L5_支撑压力位V230731_压力N5_支撑N2_当前N2_0')
- Signal('15分钟_W5M40N8L5_支撑压力位V230731_压力N5_支撑N1_当前N2_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param w: 评价分位数分布用的窗口大小
- :param m: 计算分位数所需取K线的数量。
- :param n: 最近N笔
- :param l: 分层的数量。
:return: 信号识别结果
"""
w = int(kwargs.get("w", 5))
m = int(kwargs.get("m", 40))
n = int(kwargs.get("n", 8))
l = int(kwargs.get("l", 5))

assert m > l * 2 > 2, "参数 m 必须大于 l * 2,且 l 必须大于 2"
assert w < m, "参数 w 必须小于 m"

freq = c.freq.value
k1, k2, k3 = f"{freq}_W{w}M{m}N{n}L{l}_支撑压力位V230731".split('_')
if len(c.bi_list) < n+2:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1="其他")

# 更新支撑压力位位置
cache_key_pct = "pct"
H_line, L_line = max([x.high for x in c.bi_list[-n:]]), min([x.low for x in c.bi_list[-n:]])
for i, bar in enumerate(c.bars_raw):
if cache_key_pct in bar.cache:
continue
bar.cache[cache_key_pct] = (bar.close - L_line) / (H_line - L_line)

fenweis = [x.cache[cache_key_pct] for x in get_sub_elements(c.bars_raw, n=m)]
layer = pd.qcut(fenweis, l, labels=False, duplicates='drop')
max_layer = max(layer[-w:]) + 1
min_layer = min(layer[-w:]) + 1

v1, v2, v3 = f"压力N{max_layer}", f"支撑N{min_layer}", f"当前N{layer[-1]+1}"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1, v2=v2, v3=v3)


def bar_window_ps_V230801(c: CZSC, **kwargs) -> OrderedDict:
"""指定窗口内支撑压力位分位数计算
参数模板:"{freq}_N{n}W{w}_支撑压力位V230801"
**信号逻辑:**
1. 计算最近 N 笔的最高价 NH 和最低价 NL,这个可以近似理解成价格的支撑和压力位
2. 计算并缓存最新K线的收盘价格 C 处于 NH、NL 之间的位置,计算方法为 P = (C - NL)/ (NH - NL)
3. 取最近 M 个 P 值序列,四舍五入精确到小数点后1位,作为当前K线的分位数
**信号列表:**
:param c: CZSC对象
:param kwargs: 参数字典
- :param w: 评价分位数分布用的窗口大小
- :param n: 最近N笔
:return: 信号识别结果
"""
w = int(kwargs.get("w", 5))
n = int(kwargs.get("n", 8))

freq = c.freq.value
k1, k2, k3 = f"{freq}_N{n}W{w}_支撑压力位V230801".split('_')
if len(c.bi_list) < n+2:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1="其他")

ubi = c.ubi
H_line, L_line = max([x.high for x in c.bi_list[-n:]] + [ubi['high']]), min([x.low for x in c.bi_list[-n:]] + [ubi['low']])

pcts = [int(max((x.close - L_line) / (H_line - L_line), 0) * 10) for x in c.bars_raw[-w:]]
v1, v2, v3 = f"最大N{max(pcts)}", f"最小N{min(pcts)}", f"当前N{pcts[-1]}"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1, v2=v2, v3=v3)
Loading

0 comments on commit ffc7240

Please sign in to comment.