# -*- coding: utf-8 -*-
"""
author: zengbin93
email: zeng_bin8888@163.com
create_dt: 2023/4/14 19:27
describe:
"""
from czsc.analyze import CZSC
from collections import OrderedDict
from czsc.traders.base import CzscTrader
from czsc.utils import create_single_signal, get_sub_elements
from czsc.objects import Operate, Direction, Mark
from czsc.signals.tas import update_ma_cache
[docs]def pos_ma_V230414(cat: CzscTrader, **kwargs) -> OrderedDict:
"""判断开仓后是否升破MA均线或跌破MA均线
参数模板:"{pos_name}_{freq1}#{ma_type}#{timeperiod}_持有状态V230414"
**信号逻辑:**
多头持有状态如下,反之为空头持有状态:
1. 如果持有多头,且开仓后有价格升破MA均线,则为多头升破均线;
2. 如果持有空头,且开仓后有价格跌破MA均线,则为空头跌破均线。
**信号列表:**
- 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)
[docs]def pos_fx_stop_V230414(cat: CzscTrader, **kwargs) -> OrderedDict:
"""按照开仓点附近的分型止损
参数模板:"{freq1}_{pos_name}N{n}_止损V230414"
**信号逻辑:**
多头止损逻辑如下,反之为空头止损逻辑:
1. 从多头开仓点开始,在给定对的K线周期 freq1 上向前找 N 个底分型,记为 F1
2. 将这 N 个底分型的最低点,记为 L1,如果最新价低于 L1,则止损
**信号列表:**
- Signal('日线_日线三买多头N1_止损V230414_多头止损_任意_任意_0')
- Signal('日线_日线三买多头N1_止损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"]
n = int(kwargs.get("n", 3))
k1, k2, k3 = f"{freq1}_{pos_name}N{n}_止损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]
# 多头止损逻辑
if op["op"] == Operate.LO:
fxs = [x for x in c.fx_list if x.mark == Mark.D and x.dt < op["dt"]][-n:]
if cat.latest_price < min([x.low for x in fxs]):
v1 = "多头止损"
# 空头止损逻辑
if op["op"] == Operate.SO:
fxs = [x for x in c.fx_list if x.mark == Mark.G and x.dt < op["dt"]][-n:]
if cat.latest_price > max([x.high for x in fxs]):
v1 = "空头止损"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_bar_stop_V230524(cat: CzscTrader, **kwargs) -> OrderedDict:
"""按照开仓点附近的N根K线极值止损
参数模板:"{pos_name}_{freq1}N{n}K_止损V2305224"
**信号逻辑:**
多头止损逻辑如下,反之为空头止损逻辑:
1. 从多头开仓点开始,在给定的K线周期 freq1 上向前找 N 个K线,记为 F1
2. 将这 N 个K线的最低点,记为 L1,如果最新价跌破 L1,则止损
**信号列表:**
- Signal('日线三买多头_日线N3K_止损V2305224_多头止损_任意_任意_0')
- Signal('日线三买多头_日线N3K_止损V2305224_空头止损_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- n: int,向前找的K线个数,默认为 3
:return: OrderedDict
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
n = int(kwargs.get("n", 3))
k1, k2, k3 = f"{pos_name}_{freq1}N{n}K_止损V2305224".split("_")
v1 = "其他"
assert 20 >= n >= 1, "参数 n 取值范围为 1~20"
# 如果没有持仓策略,则不产生信号
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: CZSC = 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"]][-n:]
if cat.latest_price < min([x.low for x in bars]):
v1 = "多头止损"
# 空头止损逻辑
if op["op"] == Operate.SO:
bars = [x for x in c.bars_raw[-100:] if x.dt < op["dt"]][-n:]
if cat.latest_price > max([x.high for x in bars]):
v1 = "空头止损"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]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)
[docs]def pos_fix_exit_V230624(cat: CzscTrader, **kwargs) -> OrderedDict:
"""固定比例止损,止盈
参数模板:"{pos_name}_固定{th}BP止盈止损_出场V230624"
**信号逻辑:**
以多头为例,如果持有收益超过 th 个BP,则止盈;如果亏损超过 th 个BP,则止损。
**信号列表:**
- Signal('日线三买多头_固定100BP止盈止损_出场V230624_多头止损_任意_任意_0')
- Signal('日线三买多头_固定100BP止盈止损_出场V230624_空头止损_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- n: int,向前找的K线个数,默认为 3
:return:
"""
pos_name = kwargs["pos_name"]
th = int(kwargs.get("th", 300))
k1, k2, k3 = f"{pos_name}_固定{th}BP止盈止损_出场V230624".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)
op = pos_.operates[-1]
op_price = op["price"]
if op["op"] == Operate.LO:
if cat.latest_price < op_price * (1 - th / 10000):
v1 = "多头止损"
if cat.latest_price > op_price * (1 + th / 10000):
v1 = "多头止盈"
if op["op"] == Operate.SO:
if cat.latest_price > op_price * (1 + th / 10000):
v1 = "空头止损"
if cat.latest_price < op_price * (1 - th / 10000):
v1 = "空头止盈"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_profit_loss_V230624(cat: CzscTrader, **kwargs) -> OrderedDict:
"""开仓后盈亏比达到一定比值,才允许平仓 贡献者:谌意勇
参数模板:"{pos_name}_{freq1}YKB{ykb}N{n}_盈亏比判断V230624"
**信号逻辑:**
1. 通过公式 计算盈亏比=abs(现价-开仓价)/abs(开仓价-止损价)* 10,当比值大于一定阀值时才允许平仓
**信号列表:**
- Signal('日线通道突破_60分钟YKB20N3_盈亏比判断V230624_空头止损_任意_任意_0')
- Signal('日线通道突破_60分钟YKB20N3_盈亏比判断V230624_多头止损_任意_任意_0')
- Signal('日线通道突破_60分钟YKB20N3_盈亏比判断V230624_多头达标_任意_任意_0')
- Signal('日线通道突破_60分钟YKB20N3_盈亏比判断V230624_空头达标_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- ykb: int,默认为 20, 表示2倍盈亏比,计算盈亏比=abs(现价-开仓价)/abs(开仓价-止损价)
- n: int 默认为3 止损取最近n个分型的最低点或最高点
:return:
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
ykb = int(kwargs.get("ykb", 20))
n = int(kwargs.get("n", 3))
k1, k2, k3 = f"{pos_name}_{freq1}YKB{ykb}N{n}_盈亏比判断V230624".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]
last_close = c.bars_raw[-1].close
if op["op"] == Operate.LO:
fxs = [x for x in c.fx_list if x.mark == Mark.D and x.dt < op["dt"]][-n:]
stop_price = min([x.low for x in fxs])
ykb_ = ((last_close - op["price"]) / (op["price"] - stop_price)) * 10
if ykb_ > ykb:
v1 = "多头达标"
else:
if last_close < stop_price:
v1 = "多头止损"
if op["op"] == Operate.SO:
fxs = [x for x in c.fx_list if x.mark == Mark.G and x.dt < op["dt"]][-n:]
stop_price = max([x.high for x in fxs])
ykb_ = ((last_close - op["price"]) / (op["price"] - stop_price)) * 10
if ykb_ > ykb:
v1 = "空头达标"
else:
if last_close > stop_price:
v1 = "空头止损"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_status_V230808(cat: CzscTrader, **kwargs) -> OrderedDict:
"""Position策略的持仓状态
参数模板:"{pos_name}_持仓状态_BS辅助V230808"
**信号逻辑:**
对指定的持仓策略,有三种状态:持多、持空、持币。
**信号列表:**
- Signal('日线三买多头N1_持仓状态_BS辅助V230808_持多_任意_任意_0')
- Signal('日线三买多头N1_持仓状态_BS辅助V230808_持空_任意_任意_0')
- Signal('日线三买多头N1_持仓状态_BS辅助V230808_持币_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
:return:
"""
pos_name = kwargs["pos_name"]
k1, k2, k3 = f"{pos_name}_持仓状态_BS辅助V230808".split("_")
# 如果没有持仓策略,则不产生信号
if not hasattr(cat, "positions"):
return create_single_signal(k1=k1, k2=k2, k3=k3, v1="其他")
pos = cat.get_position(pos_name)
v1 = "持币"
if len(pos.operates) == 0:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
op = pos.operates[-1]
if op["op"] == Operate.LO:
v1 = "持多"
if op["op"] == Operate.SO:
v1 = "持空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_holds_V230807(cat: CzscTrader, **kwargs) -> OrderedDict:
"""开仓后N根K线收益小于M%%,且当前收益大于T%%,平仓保本
参数模板:"{pos_name}_{freq1}N{n}M{m}T{t}_BS辅助V230807"
**信号逻辑:**
1. 针对某个开仓点,如果 N 根K线之后,收益低于 M,则认为开仓失误;
2. 开仓的失误发生后,如果市场给了逃命的机会,不贪心,等待收益大于 T 时,平仓保本;
3. 保本有两种场景:开仓后先亏损后反弹;开仓后先盈利后回落。
**信号列表:**
- Signal('日线三买多头N1_60分钟N5M50T10_BS辅助V230807_多头保本_任意_任意_0')
- Signal('日线三买多头N1_60分钟N5M50T10_BS辅助V230807_空头保本_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- n: int,最少持有K线数量,默认为 5,表示5根K线之后开始判断
- m: int,收益最小阈值,默认为 100,表示收益小于 100BP 时,需要开始判断保本单
- t: int,保本收益阈值,默认为 10,表示收益大于 10BP 时,可以平仓保本
:return:
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
n = int(kwargs.get("n", 5))
m = int(kwargs.get("m", 50))
t = int(kwargs.get("t", 10))
assert m > t > 0, "参数 m 必须大于 t"
k1, k2, k3 = f"{pos_name}_{freq1}N{n}M{m}T{t}_BS辅助V230807".split("_")
v1 = "其他"
# 如果没有持仓策略,则不产生信号
if not cat.kas or 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
if t < zdf < m:
v1 = "多头保本"
if op["op"] == Operate.SO:
zdf = (op["price"] - bars[-1].close) / op["price"] * 10000
if t < zdf < m:
v1 = "空头保本"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_holds_V240428(cat: CzscTrader, **kwargs) -> OrderedDict:
"""保本单:开仓后最大盈利超过H个BP,且当前收益低于最大盈利的T%,平仓保本
参数模板:"{pos_name}_{freq1}H{h}T{t}N{n}_保本V240428"
**信号逻辑:**
以多头保本单为例,计算过程如下:
1. 从多头开仓点开始,在给定的K线周期 freq1 上计算开仓后的最大盈利,记为 Y1;
2. 计算当前收益,记为 Y2;
3. 如果Y1 大于H,且 Y2 < Y1 * T / 100,则平仓保本。
**信号列表:**
- Signal('日线三买多头N1_60分钟H100T20N5_保本V240428_空头保本_任意_任意_0')
- Signal('日线三买多头N1_60分钟H100T20N5_保本V240428_多头保本_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- h: int,最大盈利,单位BP,默认为 100
- t: int,最大盈利的T%,默认为 20
- n: int,最少持有K线数量,默认为 5,表示5根K线之后开始判断
:return: OrderedDict
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
h = int(kwargs.get("h", 100)) # 最大盈利,单位BP
t = int(kwargs.get("t", 20)) # 最大盈利的T%
n = int(kwargs.get("n", 5)) # 最少持有K线数量,默认为 5,表示5根K线之后开始判断
k1, k2, k3 = f"{pos_name}_{freq1}H{h}T{t}N{n}_保本V240428".split("_")
v1 = "其他"
# 如果没有持仓策略,则不产生信号
if not cat.kas or 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:
y1 = (max([x.close for x in bars]) - op["price"]) / op["price"] * 10000
y2 = (bars[-1].close - op["price"]) / op["price"] * 10000
if y1 > h and y2 < y1 * t / 100:
v1 = "多头保本"
if op["op"] == Operate.SO:
y1 = (op["price"] - min([x.close for x in bars])) / op["price"] * 10000
y2 = (op["price"] - bars[-1].close) / op["price"] * 10000
if y1 > h and y2 < y1 * t / 100:
v1 = "空头保本"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_holds_V240608(cat: CzscTrader, **kwargs) -> OrderedDict:
"""保本单:多头开仓后,最低价跌破前低,当前价在成本价上方N个价位,平仓保本;空头反之。
参数模板:"{pos_name}_{freq1}W{w}N{n}_保本V240608"
**信号逻辑:**
以多头保本单为例,计算过程如下:
1. 从多头开仓点开始,在给定的K线周期 freq1 上计算开仓前 W 个K线的最低价,记为 L1;
2. 计算开仓后的最低价,记为 L2;
3. 如果 L2 < L1,且当前价比开仓价高 N 个价位,则平仓保本。
**信号列表:**
- Signal('日线三买多头N1_60分钟W20N2_保本V240608_空头保本_任意_任意_0')
- Signal('日线三买多头N1_60分钟W20N2_保本V240608_多头保本_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- w: int,开仓前W根K线,默认为 20
- n: int,成本价上方N个价位,默认为 2
:return: OrderedDict
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
w = int(kwargs.get("w", 20)) # 开仓前W根K线
n = int(kwargs.get("n", 2)) # 成本价上方N个价位
k1, k2, k3 = f"{pos_name}_{freq1}W{w}N{n}_保本V240608".split("_")
v1 = "其他"
# 如果没有持仓策略,则不产生信号
if not cat.kas or 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]
# 开仓前W根K线
w_bars = [x for x in c.bars_raw[-200:] if x.dt <= op["dt"]][-w:]
# 开仓后的K线
a_bars = [x for x in c.bars_raw[-100:] if x.dt > op["dt"]]
unique_prices = [p for x in c.bars_raw[-200:] for p in [x.high, x.low, x.close, x.open]]
unique_prices = sorted(list(set(unique_prices)))
if op["op"] == Operate.LO and w_bars:
w_low = min([x.low for x in w_bars]) # 开仓前最低价
a_low = min([x.low for x in a_bars]) # 开仓后最低价
up_prices = [x for x in unique_prices if x > op["price"]] # 成本价上方的价位
# 如果开仓后的最低价低于开仓前的最低价,且当前价比开仓价高 N 个价位,则平仓保本
if len(up_prices) > n and a_low < w_low and cat.latest_price > up_prices[n]:
v1 = "多头保本"
if op["op"] == Operate.SO and w_bars:
w_high = max([x.high for x in w_bars]) # 开仓前最高价
a_high = max([x.high for x in a_bars]) # 开仓后最高价
down_prices = [x for x in unique_prices if x < op["price"]] # 成本价下方的价位
# 如果开仓后的最高价高于开仓前的最高价,且当前价比开仓价低 N 个价位,则平仓保本
if len(down_prices) > n and a_high > w_high and cat.latest_price < down_prices[-n]:
v1 = "空头保本"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_stop_V240428(cat: CzscTrader, **kwargs) -> OrderedDict:
"""止损单,持有N根K线后,多头跌破前低或空头升破前高,平仓
参数模板:"{pos_name}_{freq1}T{t}N{n}_止损V240428"
**信号逻辑:**
以多头止损为例,计算过程如下:
1. 从多头开仓点开始,在给定的K线周期 freq1 上计算开仓 N 根K线后的最新价 close;
2. 计算开仓前的 unique_price 列表,获取低于开仓价的列表,降序排列后的第 t 个价位作为止损价 Y;
3. 如果 close < Y,则止损平仓。
**信号列表:**
- Signal('日线三买多头N1_60分钟T5N5_止损V240428_空头止损_任意_任意_0')
- Signal('日线三买多头N1_60分钟T5N5_止损V240428_多头止损_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- t: int,止损多少跳,默认为 20
- n: int,最少持有K线数量,默认为 5,表示5根K线之后开始判断
:return: OrderedDict
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
t = int(kwargs.get("t", 20)) # 止损多少跳
n = int(kwargs.get("n", 5)) # 最少持有K线数量,默认为 5,表示5根K线之后开始判断
k1, k2, k3 = f"{pos_name}_{freq1}T{t}N{n}_止损V240428".split("_")
v1 = "其他"
# 如果没有持仓策略,则不产生信号
if not cat.kas or 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]
right_bars = [x for x in c.bars_raw[-100:] if x.dt > op["dt"]]
if len(right_bars) < n:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
left_bars = [x for x in c.bars_raw if x.dt < op["dt"]]
unique_prices = [p for x in left_bars for p in [x.high, x.low, x.close, x.open]]
unique_prices = sorted(list(set(unique_prices)))
if op["op"] == Operate.LO:
low_prices = sorted([x for x in unique_prices if x < op["price"]], reverse=True)
if not low_prices:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
y = low_prices[-t] if len(low_prices) > t else low_prices[0]
if right_bars[-1].close < y:
v1 = "多头止损"
if op["op"] == Operate.SO:
high_prices = sorted([x for x in unique_prices if x > op["price"]])
if not high_prices:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
y = high_prices[t] if len(high_prices) > t else high_prices[-1]
if right_bars[-1].close > y:
v1 = "空头止损"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_take_V240428(cat: CzscTrader, **kwargs) -> OrderedDict:
"""止盈单,持有N根K线后,多头持仓期间出现T根倍量阳线或空头持仓期间出现T根倍量阴线,平仓
参数模板:"{pos_name}_{freq1}T{t}N{n}_止盈V240428"
**信号逻辑:**
以多头为例,计算过程如下:
1. 从多头开仓点后N根K线开始,寻找倍量阳线,计算数量为 C;
2. 如果 C >= T,则止盈平仓。
**信号列表:**
- Signal('日线三买多头N1_60分钟T5N5_止盈V240428_空头止盈_任意_任意_0')
- Signal('日线三买多头N1_60分钟T5N5_止盈V240428_多头止盈_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- t: int,倍量K线数量止盈,默认为 3
- n: int,最少持有K线数量,默认为 5,表示5根K线之后开始判断
:return: OrderedDict
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
t = int(kwargs.get("t", 3)) # 倍量K线数量止盈
n = int(kwargs.get("n", 5)) # 最少持有K线数量,默认为 5,表示5根K线之后开始判断
k1, k2, k3 = f"{pos_name}_{freq1}T{t}N{n}_止盈V240428".split("_")
v1 = "其他"
# 如果没有持仓策略,则不产生信号
if not cat.kas or 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:
c1 = 0
for i in range(1, len(bars)):
if bars[i].close > bars[i].open and bars[i].vol > bars[i - 1].vol * 2:
c1 += 1
if c1 >= t:
v1 = "多头止盈"
if op["op"] == Operate.SO:
c2 = 0
for i in range(1, len(bars)):
if bars[i].close < bars[i].open and bars[i].vol > bars[i - 1].vol * 2:
c2 += 1
if c2 >= t:
v1 = "空头止盈"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_stop_V240331(cat: CzscTrader, **kwargs) -> OrderedDict:
"""根据最近N根K线的最高最低价止损,追踪止损,贡献者:谢磊
参数模板:"{pos_name}_{freq1}#{n}_止损V240331"
**信号逻辑:**
以多头止损为例,计算过程如下:
1. 从多头开仓点开始,在给定的K线周期 freq1 上获取最近 N 根K线,记为 bars;
2. 计算 bars 中的最低价,记为 ll;
3. 如果当前价格 low < ll,则多头止损。
空头止损逻辑同理。
**信号列表:**
- Signal('SMA5多头_15分钟#10_止损V240331_多头止损_任意_任意_0')
- Signal('SMA5空头_15分钟#10_止损V240331_空头止损_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- n: int,观察的K线数量,默认为 10,表示观察前10根K线
:return: OrderedDict
"""
pos_name = kwargs["pos_name"]
n = int(kwargs.get("n", 10))
freq1 = kwargs["freq1"]
k1, k2, k3 = f"{pos_name}_{freq1}#{n}_止损V240331".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]
pos_ = cat.get_position(pos_name)
# 如果 pos 没有操作记录,或者最后一次操作是平仓,则不产生信号
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: CZSC = cat.kas[freq1]
op = pos_.operates[-1]
bars = get_sub_elements(c.bars_raw, di=1, n=n + 1)
_bar = bars[-1]
# 多头止损逻辑:当前价格低于前n根K线的最低价
if op["op"] == Operate.LO:
ll = min([x.low for x in bars[:-1]])
if _bar.low < ll and _bar.id > op["bid"]:
v1 = "多头止损"
# 空头止损逻辑:当前价格高于前n根K线的最高价
if op["op"] == Operate.SO:
hh = max([x.high for x in bars[:-1]])
if _bar.high > hh and _bar.id > op["bid"]:
v1 = "空头止损"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_stop_V240608(cat: CzscTrader, **kwargs) -> OrderedDict:
"""止损:多头开仓后,最低价跌破前W根K线最低价N个价位,提示止损;空头反之。
参数模板:"{pos_name}_{freq1}W{w}N{n}_止损V240608"
**信号逻辑:**
以多头止损为例,计算过程如下:
1. 从多头开仓点开始,在给定的K线周期 freq1 上计算开仓前 W 个K线的最低价,记为 L1;
2. 计算开仓后的最低价,记为 L2;
3. 如果 L2 < L1 - N 个价位,则提示多头止损信号。
空头止损逻辑同理。
**信号列表:**
- Signal('SMA5多头_15分钟W20N10_止损V240608_多头止损_任意_任意_0')
- Signal('SMA5空头_15分钟W20N10_止损V240608_空头止损_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- w: int,开仓前W根K线,默认为 20
- n: int,最低价下方N个价位,默认为 10
:return: OrderedDict
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
w = int(kwargs.get("w", 20)) # 开仓前W根K线
n = int(kwargs.get("n", 10)) # N个价位
k1, k2, k3 = f"{pos_name}_{freq1}W{w}N{n}_止损V240608".split("_")
v1 = "其他"
# 如果没有持仓策略,则不产生信号
if not cat.kas or 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]
# 开仓前W根K线
w_bars = [x for x in c.bars_raw if x.dt < op["dt"]][-w:]
# 开仓后的K线
a_bars = [x for x in c.bars_raw[-100:] if x.dt > op["dt"]]
unique_prices = [p for x in c.bars_raw[-200:] for p in [x.high, x.low, x.close, x.open]]
unique_prices = sorted(list(set(unique_prices))) # 去重并按升序排列
if op["op"] == Operate.LO and w_bars:
w_low = min([x.low for x in w_bars]) # 开仓前最低价
a_low = min([x.low for x in a_bars]) # 开仓后最低价
w_low_prices = [x for x in unique_prices if x < w_low] # 开仓前最低价下方的价位,升序排列
# 如果开仓后的最低价低于开仓前的最低价向下的 N 个价位,则提示多头止损
if len(w_low_prices) > n and a_low < w_low_prices[-n]:
v1 = "多头止损"
if op["op"] == Operate.SO and w_bars:
w_high = max([x.high for x in w_bars])
a_high = max([x.high for x in a_bars])
w_high_prices = [x for x in unique_prices if x > w_high]
if len(w_high_prices) > n and a_high > w_high_prices[n]:
v1 = "空头止损"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_stop_V240614(cat: CzscTrader, **kwargs) -> OrderedDict:
"""止损:多头开仓后,有超过N根K线的最低价在成本价下方,提示止损;空头反之。
参数模板:"{pos_name}_{freq1}N{n}_止损V240614"
**信号逻辑:**
以多头止损为例,计算过程如下:
1. 从多头开仓点开始,在给定的K线周期 freq1 上获取开仓后的所有K线,记为 bars;
2. 计算 bars 中的最低价小于开仓价的数量,记为 C;
3. 如果 C >= N,则提示多头止损信号。
空头止损逻辑同理。
**信号列表:**
- Signal('SMA5多头_15分钟N10_止损V240614_多头止损_任意_任意_0')
- Signal('SMA5空头_15分钟N10_止损V240614_空头止损_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- n: int,最低价下方N个价位,默认为 10
:return: OrderedDict
"""
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
n = int(kwargs.get("n", 10)) # N根K线
k1, k2, k3 = f"{pos_name}_{freq1}N{n}_止损V240614".split("_")
v1 = "其他"
# 如果没有持仓策略,则不产生信号
if not cat.kas or 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]
# 开仓后的K线
a_bars = [x for x in c.bars_raw if x.dt >= op["dt"]]
if op["op"] == Operate.LO and len([x for x in a_bars if x.low < op["price"]]) >= n:
v1 = "多头止损"
if op["op"] == Operate.SO and len([x for x in a_bars if x.high > op["price"]]) >= n:
v1 = "空头止损"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def pos_stop_V240717(cat: CzscTrader, **kwargs) -> OrderedDict:
"""止损:多头开仓后,有超过N根K线的最低价在成本价-ATR*0.67下方,提示止损;空头反之。贡献者:谢磊
参数模板:"{pos_name}_{freq1}N{n}T{timeperiod}_止损V240717"
**信号逻辑:**
以多头止损为例,计算过程如下:
1. 从多头开仓点开始,在给定的K线周期 freq1 上获取开仓后的所有K线,记为 bars;
2. 计算 bars 中的最低价小于(开仓价-ATR*0.67)的数量,记为 C;
3. ATR的参数为默认参数,可以调整;
3. 如果 C >= N,则提示多头止损信号。
空头止损逻辑同理。
**信号列表:**
- Signal('SMA5多头_15分钟N3T20_止损V240717_多头止损_任意_任意_0')
- Signal('SMA5空头_15分钟N3T20_止损V240717_空头止损_任意_任意_0')
:param cat: CzscTrader对象
:param kwargs: 参数字典
- pos_name: str,开仓信号的名称
- freq1: str,给定的K线周期
- n: int,最低价下方N个价位,默认为 3
:return: OrderedDict
"""
from czsc.signals.tas import update_atr_cache
pos_name = kwargs["pos_name"]
freq1 = kwargs["freq1"]
n = int(kwargs.get("n", 10)) # N根K线
timeperiod = int(kwargs.get("timeperiod", 20)) # ATR参数
c = cat.kas[freq1]
cache_key = update_atr_cache(c, timeperiod=timeperiod)
k1, k2, k3 = f"{pos_name}_{freq1}N{n}T{timeperiod}_止损V240717".split("_")
v1 = "其他"
# 如果没有持仓策略,则不产生信号
if not cat.kas or 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)
op = pos.operates[-1]
atr = [x.cache[cache_key] if x.cache.get(cache_key) is not None else 0 for x in c.bars_raw if x.dt == op["dt"]]
# 开仓后的K线
a_bars = [x for x in c.bars_raw if x.dt >= op["dt"]]
if op["op"] == Operate.LO and len([x for x in a_bars if x.low < op["price"] - atr[0] * 0.67]) >= n:
v1 = "多头止损"
if op["op"] == Operate.SO and len([x for x in a_bars if x.high > op["price"] + atr[0] * 0.67]) >= n:
v1 = "空头止损"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)