Skip to content

Commit

Permalink
V0.9.12 修复涨跌停信号识别BUG (#131)
Browse files Browse the repository at this point in the history
* 0.9.12 新增信号函数

* 0.9.12 fix bug

* 0.9.12 update bar signals

* 0.9.12 新增 开仓日盈亏平衡点 计算

* 0.9.12 update

* 0.9.12 update workflow

* 0.9.12 update

* 0.9.12 update
  • Loading branch information
zengbin93 authored Mar 14, 2023
1 parent c8c46b8 commit dcfcd06
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 61 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.11 ]
branches: [ master, V0.9.12 ]
pull_request:
branches: [ master ]

Expand Down
2 changes: 1 addition & 1 deletion czsc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from czsc.utils import get_sub_elements, get_py_namespace, freqs_sorted, x_round, import_by_name, create_grid_params


__version__ = "0.9.11"
__version__ = "0.9.12"
__author__ = "zengbin93"
__email__ = "[email protected]"
__date__ = "20230312"
Expand Down
2 changes: 2 additions & 0 deletions czsc/signals/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
bar_operate_span_V221111,
bar_zdt_V221110,
bar_zdt_V221111,
bar_zdt_V230313,
bar_cross_ps_V221112,
bar_section_momentum_V221112,
bar_vol_grow_V221112,
Expand Down Expand Up @@ -114,6 +115,7 @@

tas_boll_power_V221112,
tas_boll_bc_V221118,
tas_boll_vt_V230312,

tas_kdj_base_V221101,
tas_kdj_evc_V221201,
Expand Down
94 changes: 44 additions & 50 deletions czsc/signals/bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ def bar_end_V221111(c: CZSC, k1='60分钟') -> OrderedDict:
dt: datetime = c.bars_raw[-1].dt
v = "是" if dt.minute % m == 0 else "否"

s = OrderedDict()
signal = Signal(k1=k1, k2=k2, k3=k3, v1=v)
s[signal.key] = signal.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v)


def bar_operate_span_V221111(c: CZSC, k1: str = '开多', span=("1400", "1450")) -> OrderedDict:
Expand All @@ -59,11 +56,7 @@ def bar_operate_span_V221111(c: CZSC, k1: str = '开多', span=("1400", "1450"))

dt: datetime = c.bars_raw[-1].dt
v = "是" if k2 <= dt.strftime("%H%M") <= k3 else "否"

s = OrderedDict()
signal = Signal(k1=k1, k2=k2, k3=k3, v1=v)
s[signal.key] = signal.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v)


def bar_zdt_V221110(c: CZSC, di=1) -> OrderedDict:
Expand All @@ -73,7 +66,7 @@ def bar_zdt_V221110(c: CZSC, di=1) -> OrderedDict:
**信号逻辑:**
close等于high大于前close,近似认为是涨停;反之,跌停。
close等于high,近似认为是涨停;反之,跌停。
**信号列表:**
Expand All @@ -89,19 +82,45 @@ def bar_zdt_V221110(c: CZSC, di=1) -> OrderedDict:
if len(c.bars_raw) < di + 2:
v1 = "其他"
else:
b1, b2 = c.bars_raw[-di], c.bars_raw[-di-1]
b1 = c.bars_raw[-di]

if b1.close == b1.high > b2.close:
if b1.close == b1.high:
v1 = "涨停"
elif b1.close == b1.low < b2.close:
elif b1.close == b1.low:
v1 = "跌停"
else:
v1 = "其他"

s = OrderedDict()
v = Signal(k1=k1, k2=k2, k3=k3, v1=v1)
s[v.key] = v.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)


def bar_zdt_V230313(c: CZSC, di=1, **kwargs) -> OrderedDict:
"""计算倒数第di根K线的涨跌停信息
**信号逻辑:**
- close等于high大于等于前一根K线的close,近似认为是涨停;反之,跌停。
**信号列表:**
- Signal('15分钟_D1涨跌停_V230313_跌停_任意_任意_0')
- Signal('15分钟_D1涨跌停_V230313_涨停_任意_任意_0')
:param c: 基础周期的 CZSC 对象
:param di: 倒数第 di 根 K 线
:return: s
"""
k1, k2, k3, v1 = c.freq.value, f"D{di}涨跌停", "V230313", "其他"
if len(c.bars_raw) < di + 2:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

b1, b2 = c.bars_raw[-di], c.bars_raw[-di - 1]
if b1.close == b1.high >= b2.close:
v1 = "涨停"
elif b1.close == b1.low <= b2.close:
v1 = "跌停"

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


def bar_zdt_V221111(cat: CzscSignals, freq: str, di: int = 1) -> OrderedDict:
Expand Down Expand Up @@ -151,10 +170,7 @@ def bar_zdt_V221111(cat: CzscSignals, freq: str, di: int = 1) -> OrderedDict:
else:
v1 = "其他"

s = OrderedDict()
v = Signal(k1=k1, k2=k2, k3=k3, v1=v1)
s[v.key] = v.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)


def bar_vol_grow_V221112(c: CZSC, di: int = 2, n: int = 5) -> OrderedDict:
Expand Down Expand Up @@ -185,10 +201,7 @@ def bar_vol_grow_V221112(c: CZSC, di: int = 2, n: int = 5) -> OrderedDict:
mean_vol = sum([x.vol for x in bars[:-1]]) / n
v1 = "是" if mean_vol * 4 >= bars[-1].vol >= mean_vol * 2 else "否"

s = OrderedDict()
signal = Signal(k1=k1, k2=k2, k3=k3, v1=v1)
s[signal.key] = signal.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)


def bar_fang_liang_break_V221216(c: CZSC, di: int = 1, th=300, ma1="SMA233") -> OrderedDict:
Expand Down Expand Up @@ -236,10 +249,7 @@ def _vol_fang_liang_break(bars: List[RawBar]):
break

k1, k2, k3 = f"{c.freq.value}_D{di}TH{th}_突破{ma1.upper()}".split('_')
s = OrderedDict()
signal = Signal(k1=k1, k2=k2, k3=k3, v1=v1, v2=v2)
s[signal.key] = signal.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1, v2=v2)


def bar_mean_amount_V221112(c: CZSC, di: int = 1, n: int = 10, th1: int = 1, th2: int = 4) -> OrderedDict:
Expand Down Expand Up @@ -278,10 +288,7 @@ def bar_mean_amount_V221112(c: CZSC, di: int = 1, n: int = 10, th1: int = 1, th2
else:
logger.warning(msg)

s = OrderedDict()
signal = Signal(k1=k1, k2=k2, k3=k3, v1=v1)
s[signal.key] = signal.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)


def bar_cross_ps_V221112(c: CZSC, di=1, num=3):
Expand Down Expand Up @@ -369,10 +376,7 @@ def bar_section_momentum_V221112(c: CZSC, di: int = 1, n: int = 10, th: int = 10
v2 = "强势" if abs(bp) >= th else "弱势"
v3 = "高波动" if rate >= 3 else "低波动"

s = OrderedDict()
signal = Signal(k1=k1, k2=k2, k3=k3, v1=v1, v2=v2, v3=v3)
s[signal.key] = signal.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1, v2=v2, v3=v3)


def bar_accelerate_V221110(c: CZSC, di: int = 1, window: int = 10) -> OrderedDict:
Expand Down Expand Up @@ -413,10 +417,7 @@ def bar_accelerate_V221110(c: CZSC, di: int = 1, window: int = 10) -> OrderedDic
if c2 and green_pct:
v1 = "下跌"

s = OrderedDict()
signal = Signal(k1=k1, k2=k2, k3=k3, v1=v1)
s[signal.key] = signal.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)


def bar_accelerate_V221118(c: CZSC, di: int = 1, window: int = 13, ma1='SMA10') -> OrderedDict:
Expand All @@ -442,7 +443,6 @@ def bar_accelerate_V221118(c: CZSC, di: int = 1, window: int = 13, ma1='SMA10')
:return: 信号识别结果
"""
assert window > 3, "辨别加速,至少需要3根以上K线"
s = OrderedDict()
k1, k2, k3 = c.freq.value, f"D{di}W{window}", f"{ma1}加速"

bars = get_sub_elements(c.bars_raw, di=di, n=window)
Expand All @@ -455,9 +455,7 @@ def bar_accelerate_V221118(c: CZSC, di: int = 1, window: int = 13, ma1='SMA10')
else:
v1 = "其他"

signal = Signal(k1=k1, k2=k2, k3=k3, v1=v1)
s[signal.key] = signal.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)


def bar_zdf_V221203(c: CZSC, di: int = 1, mode='ZF', span=(300, 600)) -> OrderedDict:
Expand Down Expand Up @@ -486,11 +484,7 @@ def bar_zdf_V221203(c: CZSC, di: int = 1, mode='ZF', span=(300, 600)) -> Ordered
edge = (1 - bars[-1].close / bars[-2].close) * 10000

v1 = "满足" if t2 >= edge >= t1 else "其他"

s = OrderedDict()
signal = Signal(k1=k1, k2=k2, k3=k3, v1=v1)
s[signal.key] = signal.value
return s
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)


def bar_fake_break_V230204(c: CZSC, di=1, **kwargs) -> OrderedDict:
Expand Down
37 changes: 35 additions & 2 deletions czsc/signals/tas.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def update_boll_cache_V230228(c: CZSC, **kwargs):

for i in range(1, 6):
_c = dict(c.bars_raw[-i].cache) if c.bars_raw[-i].cache else dict()
_c.update({cache_key: {"上轨": u1[i], "中线": m[i], "下轨": l1[i]}})
_c.update({cache_key: {"上轨": u1[-i], "中线": m[-i], "下轨": l1[-i]}})
c.bars_raw[-i].cache = _c

return cache_key
Expand Down Expand Up @@ -203,9 +203,42 @@ def update_boll_cache(c: CZSC, **kwargs):
return cache_key


def tas_boll_vt_V230312(c: CZSC, di: int = 1, **kwargs) -> OrderedDict:
"""以BOLL通道为依据的多空进出场信号
**信号逻辑:**
1. 看多,当日收盘价在上轨上方,且最近max_overlap根K线中至少有一个收盘价都在上轨下方;
2. 看空,当日收盘价在下轨下方,且最近max_overlap根K线中至少有一个收盘价都在下轨上方;
**信号列表:**
- Signal('15分钟_D1BOLL20S20MO5_BS辅助V230312_看空_任意_任意_0')
- Signal('15分钟_D1BOLL20S20MO5_BS辅助V230312_看多_任意_任意_0')
:param c: CZSC对象
:param di: 信号计算截止倒数第i根K线
:return:
"""
key = update_boll_cache_V230228(c, **kwargs)
max_overlap = kwargs.get('max_overlap', 5)
k1, k2, k3 = f"{c.freq.value}_D{di}{key}MO{max_overlap}_BS辅助V230312".split('_')
v1 = "其他"
_bars = get_sub_elements(c.bars_raw, di=di, n=max_overlap + 1)
if len(_bars) < max_overlap + 1:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

if _bars[-1].close > _bars[-1].cache[key]['上轨'] and any([x.close < x.cache[key]['上轨'] for x in _bars]):
v1 = "看多"

elif _bars[-1].close < _bars[-1].cache[key]['下轨'] and any([x.close > x.cache[key]['下轨'] for x in _bars]):
v1 = "看空"

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


# MACD信号计算函数
# ======================================================================================================================

def tas_macd_base_V221028(c: CZSC, di: int = 1, key="macd", **kwargs) -> OrderedDict:
"""MACD|DIF|DEA 多空和方向信号
Expand Down
2 changes: 2 additions & 0 deletions czsc/traders/performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ def get_pairs_statistics(df_pairs: pd.DataFrame):
"每自然日收益": 0,
"每根K线收益": 0,
"盈亏平衡点": 0,
"开仓日盈亏平衡点": 0,
}
return info

Expand Down Expand Up @@ -189,6 +190,7 @@ def get_pairs_statistics(df_pairs: pd.DataFrame):
"交易得分": round(total_gain_loss_rate * win_pct, 4),
"赢面": round(single_gain_loss_rate * win_pct - (1 - win_pct), 4),
"盈亏平衡点": round(cal_break_even_point(df_pairs['盈亏比例'].to_list()), 4),
"开仓日盈亏平衡点": round(df_pairs.groupby('开仓日')['盈亏比例'].apply(cal_break_even_point).mean(), 4),
}

info['每自然日收益'] = round(info['平均单笔收益'] / info['平均持仓天数'], 2)
Expand Down
10 changes: 3 additions & 7 deletions examples/ts_check_signal_acc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,9 @@
import sys
sys.path.insert(0, '..')
import os
import numpy as np
from loguru import logger
from collections import OrderedDict
from czsc.data.ts_cache import TsDataCache
from czsc import CZSC, Signal
from czsc.traders.base import CzscTrader, check_signals_acc
from czsc.signals.tas import update_ma_cache
from czsc.utils import get_sub_elements, create_single_signal
from czsc import signals


Expand All @@ -32,15 +27,16 @@

def get_signals(cat: CzscTrader) -> OrderedDict:
s = OrderedDict({"symbol": cat.symbol, "dt": cat.end_dt, "close": cat.latest_price})
# 使用缓存来更新信号的方法
# 定义需要检查的信号
s.update(signals.tas_macd_first_bs_V221216(cat.kas['日线'], di=1))
return s


if __name__ == '__main__':
# check_signals_acc(bars, get_signals, freqs=['日线', '60分钟'])
check_signals_acc(bars, get_signals)

# 也可以指定信号的K线周期,比如只检查日线信号
# check_signals_acc(bars, get_signals, freqs=['日线'])



Expand Down

0 comments on commit dcfcd06

Please sign in to comment.