# -*- coding: utf-8 -*-
"""
author: zengbin93
email: zeng_bin8888@163.com
create_dt: 2023/5/11 18:11
describe: 琅盎的信号函数
"""
from loguru import logger
try:
import talib as ta
except:
logger.warning("ta-lib 没有正确安装,相关信号函数无法正常执行。"
"请参考安装教程 https://blog.csdn.net/qaz2134560/article/details/98484091")
import numpy as np
import pandas as pd
from typing import List
from collections import OrderedDict
from czsc.analyze import CZSC, RawBar
from czsc.utils.sig import get_sub_elements, create_single_signal
[docs]def adtm_up_dw_line_V230603(c: CZSC, **kwargs) -> OrderedDict:
"""ADTM能量异动,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}M{m}TH{th}_ADTMV230603"
**信号逻辑:**
1. 如果今天的开盘价大于昨天的开盘价,取最高价 - 开盘价、开盘价 - 昨天的开盘价这二者中最大值,
再将取出的最大值求和;反之取0,形成up_sum
2. 如果今天的开盘价小于昨天的开盘价,取开盘价 - 最低价、昨天的开盘价 -开盘价这二者中最大值,
再将取出的最大值求和;么之取0,形成dw_sum
3. 当 up_sum > dw_sum 或 最大值的差值之商小于TH 看多,反之看空
**信号列表:**
- Signal('日线_D1N30M20TH5_ADTMV230603_看空_任意_任意_0')
- Signal('日线_D1N30M20TH5_ADTMV230603_看多_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 获取K线的根数,默认为30
- :param m: 获取K线的根数,默认为20
- :param th: adtm阈值,默认为5,代表 5 / 10 = 0.5
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 30))
m = int(kwargs.get("m", 20))
th = int(kwargs.get("th", 5))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}M{m}TH{th}_ADTMV230603".split('_')
v1 = "其他"
if len(c.bars_raw) < di + max(n, m) + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
n_bars = get_sub_elements(c.bars_raw, di=di, n=n)
m_bars = get_sub_elements(c.bars_raw, di=di, n=m)
up_sum = np.sum([max(n_bars[i].high - n_bars[i].open, n_bars[i].open - n_bars[i - 1].open)
for i in range(1, len(n_bars)) if n_bars[i].open > n_bars[i - 1].open])
dw_sum = np.sum([max(m_bars[i].open - m_bars[i].low, m_bars[i - 1].open - m_bars[i].open)
for i in range(1, len(m_bars)) if m_bars[i].open < m_bars[i - 1].open])
adtm = (up_sum - dw_sum) / max(up_sum, dw_sum)
if up_sum > dw_sum or adtm > th / 10:
v1 = "看多"
if up_sum < dw_sum or adtm < th / 10:
v1 = "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def amv_up_dw_line_V230603(c: CZSC, **kwargs) -> OrderedDict:
"""AMV能量异动,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}M{m}_AMV能量V230603"
**信号逻辑:**
用成交量作为权重对开盘价和收盘价的均值进行加权移动平均。成交量越大的价格对移动平均结果的影响越大,
AMV 指标减小了成交量小的价格波动的影响。当短期 AMV 线上穿/下穿长期 AMV线时,产生买入/卖出信号。
**信号列表:**
- Signal('日线_D1N30M120_AMV能量V230603_看多_任意_任意_0')
- Signal('日线_D1N30M120_AMV能量V230603_看空_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 获取K线的根数,默认为30
- :param m: 获取K线的根数,默认为20
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 30))
m = int(kwargs.get("m", 120))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}M{m}_AMV能量V230603".split('_')
if n > m or len(c.bars_raw) < di + m + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1="其他")
n_bars = get_sub_elements(c.bars_raw, di=di, n=n)
m_bars = get_sub_elements(c.bars_raw, di=di, n=m)
amov1 = np.sum([(n_bars[i].amount * (n_bars[i].open + n_bars[i].close) / 2) for i in range(len(n_bars))])
amov2 = np.sum([(m_bars[i].amount * (m_bars[i].open + m_bars[i].close) / 2) for i in range(len(m_bars))])
vol_sum1 = np.sum([n_bars[i].amount for i in range(len(n_bars))])
vol_sum2 = np.sum([m_bars[i].amount for i in range(len(m_bars))])
amv1 = amov1 / vol_sum1
amv2 = amov2 / vol_sum2
v1 = "看多" if amv1 > amv2 else "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def asi_up_dw_line_V230603(c: CZSC, **kwargs) -> OrderedDict:
"""ASI多空分类,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}P{p}_ASI多空V230603"
**信号逻辑:**
由于 SI 的波动性比较大,所以我们一般对 SI 累计求和得到 ASI 并捕
捉 ASI 的变化趋势。一般我们不会直接看 ASI 的数值(对 SI 累计求
和的求和起点不同会导致求出 ASI 的值不同),而是会观察 ASI 的变
化方向。我们利用 ASI 与其均线的交叉来产生交易信号,上穿/下穿均
线时买入/卖出
**信号列表:**
- Signal('日线_D1N30P120_ASI多空V230603_看多_任意_任意_0')
- Signal('日线_D1N30P120_ASI多空V230603_看空_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 获取K线的根数,默认为30
- :param p: 获取K线的根数,默认为20
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 30))
p = int(kwargs.get("p", 120))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}P{p}_ASI多空V230603".split('_')
v1 = "其他"
if len(c.bars_raw) < di + p + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
_bars = get_sub_elements(c.bars_raw, di=di, n=p)
close_prices = np.array([bar.close for bar in _bars])
open_prices = np.array([bar.open for bar in _bars])
high_prices = np.array([bar.high for bar in _bars])
low_prices = np.array([bar.low for bar in _bars])
o = np.concatenate([[close_prices[0]], close_prices[:-1]])
a = np.abs(high_prices - o)
b = np.abs(low_prices - o)
c = np.abs(high_prices - np.concatenate([[low_prices[0]], low_prices[:-1]])) # type: ignore
d = np.abs(o - np.concatenate([[open_prices[0]], open_prices[:-1]]))
k = np.maximum(a, b)
m = np.maximum(high_prices - low_prices, n)
r1 = a + 0.5 * b + 0.25 * d
r2 = b + 0.5 * a + 0.25 * d
r3 = c + 0.25 * d
r4 = np.where((a >= b) & (a >= c), r1, r2)
r = np.where((c >= a) & (c >= b), r3, r4)
if (r * k / m != 0).all():
si = 50 * (close_prices - c + (c - open_prices) + 0.5 * (close_prices - open_prices)) / (r * k / m)
else:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
asi = np.cumsum(si)
v1 = "看多" if asi[-1] > np.mean(asi[-p:]) else "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def clv_up_dw_line_V230605(c: CZSC, **kwargs) -> OrderedDict:
"""CLV多空分类,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}_CLV多空V230605"
**信号逻辑:**
CLV 用来衡量收盘价在最低价和最高价之间的位置。
当CLOSE=HIGH 时,CLV=1; 当 CLOSE=LOW 时,CLV=-1;当 CLOSE位于 HIGH 和 LOW 的中点时,
CLV=0。CLV>0(<0),说明收盘价离最高(低)价更近。我们用 CLVMA 上穿/下穿 0 来产生买入/卖出信号
**信号列表:**
- Signal('日线_D1N70_CLV多空V230605_看多_任意_任意_0')
- Signal('日线_D1N70_CLV多空V230605_看空_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 获取K线的根数,默认为60
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 70))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}_CLV多空V230605".split('_')
if len(c.bars_raw) < di + 100:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1="其他")
_bars = get_sub_elements(c.bars_raw, di=di, n=n)
close = np.array([bar.close for bar in _bars])
low = np.array([bar.low for bar in _bars])
high = np.array([bar.high for bar in _bars])
clv_ma = np.mean((2 * close - low - high) / (high - low))
v1 = "看多" if clv_ma > 0 else "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def cmo_up_dw_line_V230605(c: CZSC, **kwargs) -> OrderedDict:
"""CMO能量异动,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}M{m}_CMO能量V230605"
信号逻辑:**
CMO指标用过去N天的价格上涨量和价格下跌量得到,CMO>(<)0 表示当前处于上涨(下跌)趋势,CMO 越
大(小)则当前上涨(下跌)趋势越强。我们用 CMO 上穿 30/下穿-30来产生买入/卖出信号。
信号列表:
- Signal('30分钟_D1N70M30_CMO能量V230605_看空_任意_任意_0')
- Signal('30分钟_D1N70M30_CMO能量V230605_看多_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 获取K线的根数,默认为60
- :param m: 信号预警轴,默认为30
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 70))
m = int(kwargs.get("m", 30))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}M{m}_CMO能量V230605".split('_')
v1 = "其他"
if len(c.bars_raw) < di + n + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
_bars = get_sub_elements(c.bars_raw, di=di, n=n)
up_sum = np.sum([_bars[i].close - _bars[i - 1].close for i in range(1, len(_bars))
if (_bars[i].close - _bars[i - 1].close) > 0])
dw_sum = np.sum([_bars[i - 1].close - _bars[i].close for i in range(1, len(_bars))
if (_bars[i - 1].close - _bars[i].close) > 0])
cmo = (up_sum - dw_sum) / (up_sum + dw_sum) * 100
if cmo > m:
v1 = "看多"
if cmo < -m:
v1 = "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def skdj_up_dw_line_V230611(c: CZSC, **kwargs) -> OrderedDict:
"""SKDJ随机波动指标,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}M{m}UP{up}DW{dw}_SKDJ随机波动V230611"
**信号逻辑:**
SKDJ 为慢速随机波动(即慢速 KDJ)。SKDJ 中的 K 即 KDJ 中的 D,
SKJ 中的 D 即 KDJ 中的 D 取移动平均。其用法与 KDJ 相同。
当 D<40(处于超卖状态)且 K 上穿 D 时买入,当 D>60(处于超买状
态)K 下穿 D 时卖出。
**信号列表:**
- Signal('日线_D1N233M145UP60DW40_SKDJ随机波动V230611_看多_任意_任意_0')
- Signal('日线_D1N233M145UP60DW40_SKDJ随机波动V230611_看空_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 取K线数量n必需大于m*2
- :param m: 计算均值需要的参数
- :param up: 信号预警值
- :param dw: 信号预警值
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 233))
m = int(kwargs.get("m", 89))
up = int(kwargs.get("up", 60))
dw = int(kwargs.get("dw", 40))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}M{m}UP{up}DW{dw}_SKDJ随机波动V230611".split('_')
# 计算RSV缓存
rsv_cache = f'RSV{n}'
for i, bar in enumerate(c.bars_raw):
if bar.cache.get(rsv_cache) is not None:
continue
if i < n:
n_bars = c.bars_raw[:i+1]
else:
n_bars = get_sub_elements(c.bars_raw, di=i, n=n)
min_low = min([x.low for x in n_bars])
max_high = max([x.high for x in n_bars])
bar.cache[rsv_cache] = (bar.close - min_low) / (max_high - min_low) * 100
v1 = "其他"
if len(c.bars_raw) < di + m*3 + 20 or n < m:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
bars = get_sub_elements(c.bars_raw, di=di, n=m*3 + 20)
rsv = np.array([bar.cache[rsv_cache] for bar in bars])
ma_rsv = np.convolve(rsv, np.ones(m)/m, mode='valid')
k = np.convolve(ma_rsv, np.ones(m)/m, mode='valid')
d = np.mean(k[-m:])
if dw < d < k[-1]:
v1 = "看多"
if k[-1] < d > up:
v1 = "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def bias_up_dw_line_V230618(c: CZSC, **kwargs) -> OrderedDict:
"""BIAS乖离率指标,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}M{m}P{p}TH1{th1}TH2{th2}TH3{th3}_BIAS乖离率V230618"
**信号逻辑:**
乖离率 BIAS 用来衡量收盘价与移动平均线之间的差距。
当 BIAS6 大于 3 且 BIAS12 大于 5 且 BIAS24 大于 8,
三个乖离率均进入股价强势上涨区间,产生买入信号;
当 BIAS6 小于-3 且 BIAS12 小于-5 且BIAS24 小于-8 时,
三种乖离率均进入股价强势下跌区间,产生卖出信号
**信号列表:**
- Signal('日线_D1N6M12P24TH11TH23TH35_BIAS乖离率V230618_看空_任意_任意_0')
- Signal('日线_D1N6M12P24TH11TH23TH35_BIAS乖离率V230618_看多_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 获取K线的根数,默认为30
- :param m: 获取K线的根数,默认为20
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 6))
m = int(kwargs.get("m", 12))
p = int(kwargs.get("p", 24))
th1 = int(kwargs.get("th1", 1))
th2 = int(kwargs.get("th2", 3))
th3 = int(kwargs.get("th3", 5))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}M{m}P{p}TH1{th1}TH2{th2}TH3{th3}_BIAS乖离率V230618".split('_')
v1 = "其他"
if len(c.bars_raw) < di + max(n, m, p):
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
bars1 = get_sub_elements(c.bars_raw, di=di, n=n)
bars2 = get_sub_elements(c.bars_raw, di=di, n=m)
bars3 = get_sub_elements(c.bars_raw, di=di, n=p)
bias_ma1 = np.mean([bars1[i].close for i in range(len(bars1))])
bias_ma2 = np.mean([bars2[i].close for i in range(len(bars2))])
bias_ma3 = np.mean([bars3[i].close for i in range(len(bars3))])
bias1 = (bars1[-1].close - bias_ma1) / bias_ma1 * 100
bias2 = (bars2[-1].close - bias_ma2) / bias_ma2 * 100
bias3 = (bars3[-1].close - bias_ma3) / bias_ma3 * 100
if bias1 > th1 and bias2 > th2 and bias3 > th3:
v1 = "看多"
if bias1 < -th1 and bias2 < -th2 and bias3 < -th3:
v1 = "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def dema_up_dw_line_V230605(c: CZSC, **kwargs) -> OrderedDict:
"""DEMA短线趋势指标,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}_DEMA短线趋势V230605"
**信号逻辑:**
DEMA指标是一种趋势指标,用于衡量价格趋势的方向和强度。
与其他移动平均线指标相比,DEMA指标更加灵敏,能够更快地反应价格趋势的变化,因此在短期交易中具有一定的优势。
当收盘价大于DEMA看多, 当收盘价小于DEMA看空
**信号列表:**
- Signal('日线_D1N5_DEMA短线趋势V230605_看多_任意_任意_0')
- Signal('日线_D1N5_DEMA短线趋势V230605_看空_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 获取K线的根数,默认为5
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 5))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}_DEMA短线趋势V230605".split('_')
v1 = "其他"
if len(c.bars_raw) < di + 2*n + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
short_bars = get_sub_elements(c.bars_raw, di=di, n=n)
long_bars = get_sub_elements(c.bars_raw, di=di, n=n * 2)
dema = np.mean([x.close for x in short_bars]) * 2 - np.mean([x.close for x in long_bars])
v1 = "看多" if short_bars[-1].close > dema else "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def demakder_up_dw_line_V230605(c: CZSC, **kwargs) -> OrderedDict:
"""DEMAKER价格趋势指标,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}TH{th}TL{tl}_DEMAKER价格趋势V230605"
**信号逻辑:**
DEMAKER指标的作用是用于判断价格的趋势和力度
当 demaker>0.6 时上升趋势强烈,当 demaker<0.4 时下跌趋势强烈。
当 demaker 上穿 0.6/下穿 0.4 时产生买入/卖出信号。
**信号列表:**
- Signal('日线_D1N105TH5TL5_DEMAKER价格趋势V230605_看多_任意_任意_0')
- Signal('日线_D1N105TH5TL5_DEMAKER价格趋势V230605_看空_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 获取K线的根数,默认为105
- :param th: 开多阈值,默认为6
- :param tl: 开空阈值,默认为4
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 105))
th = int(kwargs.get("th", 5))
tl = int(kwargs.get("tl", 5))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}TH{th}TL{tl}_DEMAKER价格趋势V230605".split('_')
# 增加一个约束,如果K线数量不足时直接返回
v1 = "其他"
if len(c.bars_raw) < di + n + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
bars = get_sub_elements(c.bars_raw, di=di, n=n)
demax = np.mean([bars[i].high - bars[i-1].high for i in
range(1, len(bars)) if bars[i].high - bars[i-1].high > 0])
demin = np.mean([bars[i-1].low - bars[i].low for i in
range(1, len(bars)) if bars[i-1].low - bars[i].low > 0])
demaker = demax / (demax + demin)
if demaker > th / 10:
v1 = "看多"
if demaker < tl / 10:
v1 = "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def emv_up_dw_line_V230605(c: CZSC, **kwargs) -> OrderedDict:
"""EMV简易波动指标,贡献者:琅盎
参数模板:"{freq}_D{di}_EMV简易波动V230605"
**信号逻辑:**
emv 综合考虑了成交量和价格(中间价)的变化。
emv>0 则多头处于优势,emv 上升说明买方力量在增大;
emv<0 则空头处于优势,emv 下降说明卖方力量在增大。
如果 emv 上穿 0,则产生买入信号;
如果 emv 下穿 0,则产生卖出信号。
**信号列表:**
- Signal('日线_D1_EMV简易波动V230605_看多_任意_任意_0')
- Signal('日线_D1_EMV简易波动V230605_看空_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}_EMV简易波动V230605".split('_')
# 增加一个约束,如果K线数量不足时直接返回
v1 = "其他"
if len(c.bars_raw) < di + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
_bars = get_sub_elements(c.bars_raw, di=di, n=2)
mid_pt_move = (_bars[-1].high + _bars[-1].low) / 2 - (_bars[-2].high + _bars[-2].low) / 2
box_ratio = _bars[-1].vol / (_bars[-1].high - _bars[-1].low + 1e-9)
emv = mid_pt_move / box_ratio
v1 = "看多" if emv > 0 else "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def er_up_dw_line_V230604(c: CZSC, **kwargs) -> OrderedDict:
"""ER价格动量指标,贡献者:琅盎
参数模板:"{freq}_D{di}W{w}N{n}_ER价格动量V230604"
**信号逻辑:**
er 为动量指标。用来衡量市场的多空力量对比。在多头市场,
人们会更贪婪地在接近高价的地方买入,BullPower 越高则当前
多头力量越强;而在空头市场,人们可能因为恐惧而在接近低价
的地方卖出。BearPower 越低则当前空头力量越强。当两者都大
于 0 时,反映当前多头力量占据主导地位;两者都小于 0 则反映
空头力量占据主导地位。
如果 BearPower 上穿 0,则产生买入信号;
如果 BullPower 下穿 0,则产生卖出信号。
**信号列表:**
- Signal('日线_D1W21N10_ER价格动量V230604_均线下方_第10层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线下方_第9层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线下方_第8层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线上方_第5层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线上方_第1层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线上方_第10层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线上方_第2层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线上方_第6层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线上方_第7层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线上方_第8层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线上方_第9层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线上方_第4层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线下方_第5层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线下方_第7层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线下方_第3层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线下方_第2层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线下方_第6层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线下方_第1层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线下方_第4层_任意_0')
- Signal('日线_D1W21N10_ER价格动量V230604_均线上方_第3层_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 获取K线的根数,默认为105
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
w = int(kwargs.get("w", 60))
n = int(kwargs.get("n", 10))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}W{w}N{n}_ER价格动量V230604".split('_')
cache_key = f"ER{w}"
for i, bar in enumerate(c.bars_raw, 1):
if cache_key in bar.cache:
continue
_bars = c.bars_raw[i-w:i]
ma = np.mean([x.close for x in _bars])
bull_power = bar.high - ma if bar.high > ma else bar.low - ma
bar.cache.update({cache_key: bull_power})
v1 = "其他"
if len(c.bars_raw) < di + w + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
_bars = get_sub_elements(c.bars_raw, di=di, n=w*10)
factors = [x.cache[cache_key] for x in _bars]
factors = [x for x in factors if x * factors[-1] > 0]
v1 = "均线上方" if factors[-1] > 0 else "均线下方"
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=v1, v2=f"第{q}层")
[docs]def obvm_line_V230610(c: CZSC, **kwargs) -> OrderedDict:
"""OBV能量指标,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}M{m}_OBV能量V230610"
**信号逻辑:**
OBV 指标把成交量分为正的成交量(价格上升时的成交量)和负的成交量(价格下降时)的成交量。
OBV 就是分了正负之后的成交量的累计和。
首先,根据传入的参数 di、n 和 m,从 CZSC 对象中获取对应的 K 线数据,然后计算 OBV 序列。
接着,使用 talib 库中的 EMA 函数计算 OBV 序列的短期和长期指数移动平均线,
最后根据两条移动平均线的大小关系判断看多或看空信号。
飞书文档:https://s0cqcxuy3p.feishu.cn/wiki/CEMLwa46Ii1sJZkT3IVcJKAwntc
**信号列表:**
- Signal('日线_D1N10M30_OBV能量V230610_看空_任意_任意_0')
- Signal('日线_D1N10M30_OBV能量V230610_看多_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: short窗口大小。
- :param m: long窗口大小。
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 10))
m = int(kwargs.get("m", 30))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}M{m}_OBV能量V230610".split('_')
v1 = "其他"
# 计算OBV,缓存到bar.cache中
cache_key = "OBV"
for i in range(1, len(c.bars_raw)):
bar1, bar2 = c.bars_raw[i - 1], c.bars_raw[i]
if cache_key not in bar1.cache:
last_obv = bar1.vol if bar1.close > bar1.open else -bar1.vol
bar1.cache[cache_key] = last_obv
else:
last_obv = bar1.cache[cache_key]
if cache_key not in bar2.cache:
cur_obv = bar2.vol if bar2.close > bar2.open else -bar2.vol
bar2.cache[cache_key] = last_obv + cur_obv
if len(c.bars_raw) < di + max(n, m) + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
bars = get_sub_elements(c.bars_raw, di=di, n=max(n, m) + 10)
obv_seq = np.array([x.cache[cache_key] for x in bars], dtype=np.float64)
ema_n1 = ta.EMA(obv_seq, n)[-1]
ema_n2 =ta.EMA(obv_seq, m)[-1]
v1 = "看多" if ema_n1 > ema_n2 else "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def obv_up_dw_line_V230719(c: CZSC, **kwargs) -> OrderedDict:
"""OBV能量指标,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}M{m}MO{max_overlap}_OBV能量V230719"
**信号逻辑:**
OBV 指标把成交量分为正的成交量(价格上升时的成交量)和负的成交量(价格下降时)的成交量。
OBV 就是分了正负之后的成交量的累计和。
1. 先定义OBVM,OBVM是 OBV 7天的指数平均。
2. 再定义一条信号线Signal line,这条线是OBVM 10天的指数平均。
其中的「7天」和「10天」都是参数,根据你的交易时间级别设置,设置的越小,OBVM对成交量的变化越敏感,
产生的交易信号也就越多。
开多仓的规则:当OBVM上穿Signal line,开多仓;当OBVM下穿Signal line,平仓。这个规则只捕捉上涨趋势。
**信号列表:**
- Signal('日线_D1N7M10MO3_OBV能量V230719_看多_任意_任意_0')
- Signal('日线_D1N7M10MO3_OBV能量V230719_看空_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: short窗口大小。
- :param m: long窗口大小。
- :param max_overlap: 信号计算时,最大重叠K线数量。
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 7))
m = int(kwargs.get("m", 10))
max_overlap = int(kwargs.get("max_overlap", 3))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}M{m}MO{max_overlap}_OBV能量V230719".split('_')
v1 = "其他"
# 计算OBV,缓存到bar.cache中
cache_key = "OBV"
for i in range(1, len(c.bars_raw)):
bar1, bar2 = c.bars_raw[i - 1], c.bars_raw[i]
if cache_key not in bar1.cache:
last_obv = bar1.vol if bar1.close > bar1.open else -bar1.vol
bar1.cache[cache_key] = last_obv
else:
last_obv = bar1.cache[cache_key]
if cache_key not in bar2.cache:
cur_obv = bar2.vol if bar2.close > bar2.open else -bar2.vol
bar2.cache[cache_key] = last_obv + cur_obv
min_k_num = di + max(n, m) + max_overlap + 10
if len(c.bars_raw) < min_k_num:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
bars = get_sub_elements(c.bars_raw, di=di, n=min_k_num)
obv_seq = np.array([x.cache[cache_key] for x in bars], dtype=np.float64)
obvm = ta.EMA(obv_seq, n)
sig_ = ta.EMA(obvm, m)
if obvm[-1] > sig_[-1] and obvm[-max_overlap] < sig_[-max_overlap]:
v1 = "看多"
elif obvm[-1] < sig_[-1] and obvm[-max_overlap] > sig_[-max_overlap]:
v1 = "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def cvolp_up_dw_line_V230612(c: CZSC, **kwargs) -> OrderedDict:
"""CVOLP动量变化率指标,贡献者:琅盎
参数模板:"{freq}_D{di}N{n}M{m}UP{up}DW{dw}_CVOLP动量变化率V230612"
**信号逻辑:**
成交量移动平均平滑变化率。
先计算了成交量的N周期指数移动平均线,然后计算了EMAP的M周期前的值,最后计算了CVOLP的值。
CVOLP 上穿 up 买入,下穿 dw 卖出。
**信号列表:**
- Signal('日线_D1N13M21UP5DW5_CVOLP动量变化率V230612_看多_任意_任意_0')
- Signal('日线_D1N13M21UP5DW5_CVOLP动量变化率V230612_看空_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 取K线数量
- :param m: 信号预警值
- :param up: 看多信号预警值
- :param dw: 看空信号预警值
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 34))
m = int(kwargs.get("m", 55))
up = int(kwargs.get("up", 5))
dw = int(kwargs.get("dw", 5))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}M{m}UP{up}DW{dw}_CVOLP动量变化率V230612".split('_')
# 增加一个约束,如果K线数量不足时直接返回
v1 = "其他"
if len(c.bars_raw) < di + n + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
bars = get_sub_elements(c.bars_raw, di=di, n=n + m)
volume = np.array([bar.vol for bar in bars])
n_weights = np.exp(np.linspace(-1., 0., n))
n_weights /= n_weights.sum()
emap = np.convolve(volume, n_weights, mode='full')[:len(volume)]
emap[:n] = emap[n]
sroc = (emap - np.roll(emap, m))[-1] / np.roll(emap, m)[-1]
if sroc > up / 100:
v1 = "看多"
if sroc < -dw / 100:
v1 = "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def ntmdk_V230824(c: CZSC, **kwargs) -> OrderedDict:
"""NTMDK多空指标,贡献者:琅盎
参数模板:"{freq}_D{di}M{m}_NTMDK多空V230824"
**信号逻辑:**
此信号函数的逻辑非常简单,流传于股市中有一句话:日日新高日日持股,
那么此信号函数利用的是收盘价和M日前的收盘价进行比较,如果差值为正
即多头成立,反之空头成立。
**信号列表:**
- Signal('日线_D1M10_NTMDK多空V230824_看空_任意_任意_0')
- Signal('日线_D1M10_NTMDK多空V230824_看多_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param m: m天前的价格
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
m = int(kwargs.get("m", 10))
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}M{m}_NTMDK多空V230824".split('_')
v1 = "其他"
if len(c.bars_raw) < di + m + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
bars = get_sub_elements(c.bars_raw, di=di, n=m)
v1 = "看多" if bars[-1].close > bars[0].close else "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
[docs]def kcatr_up_dw_line_V230823(c: CZSC, **kwargs) -> OrderedDict:
"""用ATR波幅构造上下轨,收盘价突破判断多空 贡献者:琅盎
参数模板:"{freq}_D{di}N{n}M{m}T{th}_KCATR多空V230823"
**信号逻辑:**
与布林带类似,都是用价格的移动平均构造中轨,不同的是表示波幅
的方法,这里用 atr 来作为波幅构造上下轨。价格突破上轨,
可看成新的上升趋势,买入;价格突破下轨,
**信号列表:**
- Signal('日线_D1N30M16T2_KCATR多空V230823_看多_任意_任意_0')
- Signal('日线_D1N30M16T2_KCATR多空V230823_看空_任意_任意_0')
:param c: CZSC对象
:param kwargs: 参数字典
- :param di: 信号计算截止倒数第i根K线
- :param n: 获取K线的根数进行ATR计算,默认为30
- :param m: 获取K线的根数进行均价计算,默认为16
- :param th: 突破ATR的倍数,默认为2
:return: 信号识别结果
"""
di = int(kwargs.get("di", 1))
n = int(kwargs.get("n", 30))
m = int(kwargs.get("m", 16))
th = int(kwargs.get("th", 2)) # 突破ATR的倍数
freq = c.freq.value
k1, k2, k3 = f"{freq}_D{di}N{n}M{m}T{th}_KCATR多空V230823".split('_')
v1 = "其他"
if len(c.bars_raw) < di + max(m, n) + 10:
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)
n_bars = get_sub_elements(c.bars_raw, di=di, n=n)
m_bars = get_sub_elements(c.bars_raw, di=di, n=m)
atr = np.mean([
max(
abs(n_bars[i].high - n_bars[i].low),
abs(n_bars[i].high - n_bars[i - 1].close),
abs(n_bars[i].low - n_bars[i - 1].close),
)
for i in range(1, len(n_bars))
])
middle = np.mean([x.close for x in m_bars])
if m_bars[-1].close > middle + atr * th:
v1 = "看多"
elif m_bars[-1].close < middle - atr * th:
v1 = "看空"
return create_single_signal(k1=k1, k2=k2, k3=k3, v1=v1)