Skip to content

Commit

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

* 0.9.19 update

* 0.9.19 update

* 0.9.19 update

* 0.9.19 update

* 0.9.19 update

* 0.9.19 新增信号函数

* 0.9.19 新增截面评价方法

* 0.9.19 update

* 0.9.19 新增 streamlit 页面

* 0.9.19 新增信号函数

* 0.9.19 更新文档

* 0.9.19 更新文档
  • Loading branch information
zengbin93 authored May 13, 2023
1 parent 9ddd04e commit ff668fa
Show file tree
Hide file tree
Showing 30 changed files with 1,094 additions and 2,373 deletions.
5 changes: 3 additions & 2 deletions czsc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@
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, StocksDaySensor, ThsConceptsSensor, SignalsPerformance


__version__ = "0.9.18"
__version__ = "0.9.19"
__author__ = "zengbin93"
__email__ = "[email protected]"
__date__ = "20230419"
__date__ = "20230428"


def welcome():
Expand Down
2 changes: 1 addition & 1 deletion czsc/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,6 @@ def fx_list(self) -> List[FX]:
fxs.extend(bi_.fxs[1:])
ubi = self.ubi_fxs
for x in ubi:
if not fxs or x.dt > fxs[-1].raw_bars[0].dt:
if not fxs or x.dt > fxs[-1].dt:
fxs.append(x)
return fxs
3 changes: 3 additions & 0 deletions czsc/connectors/qmt_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ def get_symbols(step):
'510300.SH', '510500.SH', '510050.SH', '159992.SZ', '159985.SZ',
'159981.SZ', '159949.SZ', '159915.SZ'],
}
if step.upper() == 'ALL':
return stocks_map['index'] + stocks_map['stock'] + stocks_map['etfs']

return stocks_map[step]


Expand Down
5 changes: 4 additions & 1 deletion czsc/connectors/research.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ def get_symbols(name, **kwargs):
:param kwargs:
:return:
"""
files = glob.glob(os.path.join(cache_path, name, "*.parquet"))
if name.upper() == 'ALL':
files = glob.glob(os.path.join(cache_path, "*", "*.parquet"))
else:
files = glob.glob(os.path.join(cache_path, name, "*.parquet"))
return [os.path.basename(x).replace('.parquet', '') for x in files]


Expand Down
1 change: 1 addition & 0 deletions czsc/data/ts_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ def trade_cal(self):
df = pd.read_feather(file_cache)
else:
df = pro.trade_cal(exchange='', start_date='19900101', end_date="20300101")
df = df.sort_values('cal_date', ascending=True).reset_index(drop=True)
df.to_feather(file_cache)
return df

Expand Down
5 changes: 5 additions & 0 deletions czsc/signals/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
bar_weekday_V230328,
bar_r_breaker_V230326,
bar_dual_thrust_V230403,
bar_single_V230506,
bar_triple_V230506,
)

from czsc.signals.jcc import (
Expand Down Expand Up @@ -133,6 +135,7 @@
tas_ma_base_V230313,
tas_ma_round_V221206,
tas_double_ma_V221203,
tas_double_ma_V230511,

tas_boll_power_V221112,
tas_boll_bc_V221118,
Expand Down Expand Up @@ -160,4 +163,6 @@

from czsc.signals.pos import (
pos_fx_stop_V230414,
pos_ma_V230414,
pos_holds_V230414,
)
100 changes: 100 additions & 0 deletions czsc/signals/bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
create_dt: 2022/11/11 20:18
describe: bar 作为前缀,代表信号属于基础 K 线信号
"""
import pandas as pd
import numpy as np
from datetime import datetime
from typing import List
Expand All @@ -18,6 +19,105 @@
from czsc.signals.tas import update_ma_cache


def bar_single_V230506(c: CZSC, **kwargs) -> OrderedDict:
"""单K趋势因子辅助判断买卖点
参数模板:"{freq}_D{di}单K趋势N{n}_BS辅助V230506"
**信号逻辑:**
1. 定义趋势因子:(收盘价 / 开盘价 -1) / 成交量
2. 选取最近100根K线,计算趋势因子,分成n层
**信号列表:**
- Signal('15分钟_D1单K趋势N5_BS辅助V230506_第3层_任意_任意_0')
- Signal('15分钟_D1单K趋势N5_BS辅助V230506_第4层_任意_任意_0')
- Signal('15分钟_D1单K趋势N5_BS辅助V230506_第2层_任意_任意_0')
- Signal('15分钟_D1单K趋势N5_BS辅助V230506_第1层_任意_任意_0')
- Signal('15分钟_D1单K趋势N5_BS辅助V230506_第5层_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
:return: 返回信号结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 5))
assert n <= 20, "n 的取值范围为 1~20,分层数量不宜太多"
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}单K趋势N{n}_BS辅助V230506".split('_')
v1 = '其他'
if len(c.bars_raw) < 100 + di:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

bars = get_sub_elements(c.bars_raw, di=di, n=100)
factors = [(x.close / x.open - 1) / x.vol for x in bars]
q = pd.cut(factors, n, labels=list(range(1, n+1)), precision=5, duplicates='drop')[-1]
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=f"第{q}层")


def bar_triple_V230506(c: CZSC, **kwargs) -> OrderedDict:
"""三K加速形态配合成交量变化
参数模板:"{freq}_D{di}三K加速_裸K形态V230506"
**信号逻辑:**
1. 连续三根阳线,【三连涨】,如果高低点不断创新高,【新高涨】
2. 连续三根阴线,【三连跌】,如果高低点不断创新低,【新低跌】
3. 加入成交量变化的判断,成交量逐渐放大 或 成交量逐渐缩小
**信号列表:**
- Signal('15分钟_D1三K加速_裸K形态V230506_三连涨_量柱无序_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_三连跌_量柱无序_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_新高涨_依次放量_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_新低跌_依次缩量_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_新低跌_量柱无序_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_三连涨_依次放量_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_三连跌_依次放量_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_新低跌_依次放量_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_三连跌_依次缩量_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_新高涨_依次缩量_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_新高涨_量柱无序_任意_0')
- Signal('15分钟_D1三K加速_裸K形态V230506_三连涨_依次缩量_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
:return: 返回信号结果
"""
di = int(kwargs.get("di", 1))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}三K加速_裸K形态V230506".split('_')
v1 = '其他'
if len(c.bars_raw) < 7:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

b3, b2, b1 = get_sub_elements(c.bars_raw, di=di, n=3)

if b1.close > b1.open and b2.close > b2.open and b3.close > b3.open:
v1 = '三连涨'
if b1.high > b2.high > b3.high and b1.low > b2.low > b3.low:
v1 = "新高涨"

if b1.close < b1.open and b2.close < b2.open and b3.close < b3.open:
v1 = '三连跌'
if b1.high < b2.high < b3.high and b1.low < b2.low < b3.low:
v1 = "新低跌"

if v1 == '其他':
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

if b1.vol > b2.vol > b3.vol:
v2 = '依次放量'
elif b1.vol < b2.vol < b3.vol:
v2 = '依次缩量'
else:
v2 = '量柱无序'

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


def bar_end_V221111(c: CZSC, k1='60分钟') -> OrderedDict:
"""分钟 K 线结束
Expand Down
119 changes: 118 additions & 1 deletion czsc/signals/pos.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,68 @@
from czsc.traders.base import CzscTrader
from czsc.utils import create_single_signal
from czsc.objects import Operate, Direction, Mark
from czsc.signals.tas import update_ma_cache


def pos_ma_V230414(cat: CzscTrader, **kwargs) -> OrderedDict:
"""判断开仓后是否升破MA均线或跌破MA均线
参数模板:"{pos_name}_{freq1}#{ma_type}#{timeperiod}_持有状态V230414"
**信号逻辑:**
多头止损逻辑如下,反之为空头止损逻辑:
1. 从多头开仓点开始,在给定对的K线周期 freq1 上向前找 N 个底分型,记为 F1
2. 将这 N 个底分型的最低点,记为 L1,如果 L1 的价格低于开仓点的价格,则止损
**信号列表:**
- Signal('日线三买多头N1_60分钟#SMA#5_持有状态V230414_多头_升破均线_任意_0')
- Signal('日线三买多头N1_60分钟#SMA#5_持有状态V230414_空头_跌破均线_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- n: int,向前找的分型个数,默认为 3
:return:
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
ma_type = kwargs.get("ma_type", "SMA").upper()
timeperiod = int(kwargs.get("timeperiod", 5))
k1, k2, k3 = f"{pos_name}_{freq1}#{ma_type}#{timeperiod}_持有状态V230414".split("_")
v1, v2 = '其他', '其他'
key = update_ma_cache(cat.kas[freq1], ma_type=ma_type, timeperiod=timeperiod)
# 如果没有持仓策略,则不产生信号
if not hasattr(cat, "positions"):
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

pos = [x for x in cat.positions if x.name == pos_name][0]
if len(pos.operates) == 0 or pos.operates[-1]['op'] in [Operate.SE, Operate.LE]:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

c = cat.kas[freq1]
op = pos.operates[-1]

# 多头止损逻辑
if op['op'] == Operate.LO:
bars = [x for x in c.bars_raw[-100:] if x.dt > op['dt']]
for x in bars:
if x.close > x.cache[key]:
v1, v2 = '多头', '升破均线'
break

# 空头止损逻辑
if op['op'] == Operate.SO:
bars = [x for x in c.bars_raw[-100:] if x.dt > op['dt']]
for x in bars:
if x.close < x.cache[key]:
v1, v2 = '空头', '跌破均线'
break

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


def pos_fx_stop_V230414(cat: CzscTrader, **kwargs) -> OrderedDict:
Expand Down Expand Up @@ -64,4 +126,59 @@ def pos_fx_stop_V230414(cat: CzscTrader, **kwargs) -> OrderedDict:
if cat.latest_price > max([x.high for x in fxs]):
v1 = '空头止损'

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



def pos_holds_V230414(cat: CzscTrader, **kwargs) -> OrderedDict:
"""开仓后N根K线涨幅小于M%%,则平仓
参数模板:"{pos_name}_{freq1}N{n}M{m}_趋势判断V230414"
**信号逻辑:**
1. 找出开仓后的 N 根K线,计算涨幅,如果涨幅小于 M%%,则平仓
2. 这里面的逻辑是,如果开仓后的 N 根K线涨幅小于 M%%,则说明趋势不明朗,平仓等待
**信号列表:**
- Signal('日线三买多头N1_60分钟N5M100_趋势判断V230414_多头存疑_任意_任意_0')
- Signal('日线三买多头N1_60分钟N5M100_趋势判断V230414_多头良好_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- n: int,最少持有K线数量,默认为 5,表示5根K线之后开始判断趋势
- m: int,涨幅阈值,默认为 100,表示涨幅小于 100BP 时,平仓
:return:
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
n = int(kwargs.get('n', 5))
m = int(kwargs.get('m', 100))
k1, k2, k3 = f"{pos_name}_{freq1}N{n}M{m}_趋势判断V230414".split("_")
v1 = '其他'
# 如果没有持仓策略,则不产生信号
if not hasattr(cat, "positions"):
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

pos = [x for x in cat.positions if x.name == pos_name][0]
if len(pos.operates) == 0 or pos.operates[-1]['op'] in [Operate.SE, Operate.LE]:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

c = cat.kas[freq1]
op = pos.operates[-1]
bars = [x for x in c.bars_raw[-100:] if x.dt > op['dt']]
if len(bars) < n:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)

if op['op'] == Operate.LO:
zdf = (bars[-1].close - op['price']) / op['price'] * 10000
v1 = '多头存疑' if zdf < m else '多头良好'

if op['op'] == Operate.SO:
zdf = (op['price'] - bars[-1].close) / op['price'] * 10000
v1 = '空头存疑' if zdf < m else '空头良好'

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

0 comments on commit ff668fa

Please sign in to comment.