692 lines
17 KiB
Python
692 lines
17 KiB
Python
#!/usr/bin/python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
import numpy as np
|
||
import pandas as pd
|
||
|
||
|
||
def EMA(number, n):
|
||
return pd.Series(number).ewm(alpha=2 / (n + 1), adjust=True).mean()
|
||
|
||
|
||
def MA(number, n):
|
||
return pd.Series.rolling(number, n).mean()
|
||
|
||
|
||
def SMA(number, n, m=1):
|
||
_df = number.fillna(0)
|
||
return pd.Series(_df).ewm(com=n - m, adjust=True).mean()
|
||
|
||
|
||
def RM_SMA(DF, N, M):
|
||
DF = DF.fillna(0)
|
||
z = len(DF)
|
||
var = np.zeros(z)
|
||
var[0] = DF[0]
|
||
for i in range(1, z):
|
||
var[i] = (DF[i] * M + var[i - 1] * (N - M)) / N
|
||
for i in range(z):
|
||
DF[i] = var[i]
|
||
return DF
|
||
|
||
|
||
def ATR(close, high, low, n):
|
||
"""
|
||
真实波幅
|
||
:param close:
|
||
:param high:
|
||
:param low:
|
||
:param n:
|
||
:return:
|
||
"""
|
||
c, h, l_ = close, high, low
|
||
mtr = MAX(MAX((h - l_), ABS(REF(c, 1) - h)), ABS(REF(c, 1) - l_))
|
||
atr = MA(mtr, n)
|
||
return pd.DataFrame({'MTR': mtr, 'ATR': atr})
|
||
|
||
|
||
def HHV(number, n):
|
||
return pd.Series.rolling(number, n).max()
|
||
|
||
|
||
def LLV(number, n):
|
||
return pd.Series.rolling(number, n).min()
|
||
|
||
|
||
def SUM(number, n):
|
||
return pd.Series.rolling(number, n).sum()
|
||
|
||
|
||
def ABS(number):
|
||
return np.abs(number)
|
||
|
||
|
||
def MAX(A, B):
|
||
return np.maximum(A, B)
|
||
|
||
|
||
def MIN(A, B):
|
||
var = IF(A < B, A, B)
|
||
return var
|
||
|
||
|
||
def IF(COND, V1, V2):
|
||
var = np.flip(np.where(COND, V1, V2))
|
||
return pd.Series(var)[::-1]
|
||
|
||
|
||
def REF(DF, N):
|
||
var = DF.diff(N)
|
||
var = DF - var
|
||
return var
|
||
|
||
|
||
def STD(number, n):
|
||
return pd.Series.rolling(number, n).std()
|
||
|
||
|
||
def MACD(close, f, s, m):
|
||
"""
|
||
|
||
:param close:
|
||
:param f:
|
||
:param s:
|
||
:param m:
|
||
:return:
|
||
"""
|
||
EMAFAST = EMA(close, f)
|
||
EMASLOW = EMA(close, s)
|
||
DIFF = EMAFAST - EMASLOW
|
||
DEA = EMA(DIFF, m)
|
||
MACD = (DIFF - DEA) * 2
|
||
return pd.DataFrame({
|
||
'DIFF': round(DIFF, 2),
|
||
'DEA': round(DEA, 2), 'MACD': round(MACD, 2)})
|
||
|
||
|
||
def KDJ(close, high, low, n, m1, m2):
|
||
"""
|
||
|
||
:param close:
|
||
:param high:
|
||
:param low:
|
||
:param n:
|
||
:param m1:
|
||
:param m2:
|
||
:return:
|
||
"""
|
||
c, h, l = close, high, low
|
||
RSV = (c - LLV(l, n)) / (HHV(h, n) - LLV(l, n)) * 100
|
||
K = SMA(RSV, m1, 1)
|
||
D = SMA(K, m2, 1)
|
||
J = 3 * K - 2 * D
|
||
return pd.DataFrame({'KDJ_K': round(K, 2), 'KDJ_D': round(D, 2), 'KDJ_J': round(J, 2)})
|
||
|
||
|
||
def OSC(close, n, m):
|
||
"""
|
||
变动速率线
|
||
:param close:
|
||
:param n:
|
||
:param m:
|
||
:return:
|
||
"""
|
||
c = close
|
||
OS = (c - MA(c, n)) * 100
|
||
MAOSC = EMA(OS, m)
|
||
return pd.DataFrame({'OSC': OS, 'MAOSC': MAOSC})
|
||
|
||
|
||
def BBI(close, N1, N2, N3, N4):
|
||
"""
|
||
多空指标
|
||
:param close:
|
||
:param N1:
|
||
:param N2:
|
||
:param N3:
|
||
:param N4:
|
||
:return:
|
||
"""
|
||
bbi = (MA(close, N1) + MA(close, N2) + MA(close, N3) + MA(close, N4)) / 4
|
||
return pd.DataFrame({'BBI': round(bbi, 2)})
|
||
|
||
|
||
def BBIBOLL(close, n, m, n1=3, n2=6, n3=12, n4=24):
|
||
"""
|
||
多空布林线
|
||
:param close:
|
||
:param n1:
|
||
:param n2:
|
||
:param n3:
|
||
:param n4:
|
||
:param n:
|
||
:param m:
|
||
:return:
|
||
"""
|
||
bbi_boll = BBI(close, n1, n2, n3, n4)['BBI']
|
||
UPER = bbi_boll + m * STD(bbi_boll, n)
|
||
DOWN = bbi_boll - m * STD(bbi_boll, n)
|
||
return pd.DataFrame({'BBIBOLL': round(bbi_boll, 2), 'UPER': round(UPER, 2), 'DOWN': round(DOWN, 2)})
|
||
|
||
|
||
def PBX(close, n1, n2, n3, n4, n5, n6):
|
||
"""
|
||
瀑布线
|
||
:param close:
|
||
:param n1:
|
||
:param n2:
|
||
:param n3:
|
||
:param n4:
|
||
:param n5:
|
||
:param n6:
|
||
:return:
|
||
"""
|
||
c = close
|
||
PBX1 = (EMA(c, n1) + MA(c, 2 * n1) + MA(c, 4 * n1)) / 3
|
||
PBX2 = (EMA(c, n2) + MA(c, 2 * n2) + MA(c, 4 * n2)) / 3
|
||
PBX3 = (EMA(c, n3) + MA(c, 2 * n3) + MA(c, 4 * n3)) / 3
|
||
PBX4 = (EMA(c, n4) + MA(c, 2 * n4) + MA(c, 4 * n4)) / 3
|
||
PBX5 = (EMA(c, n5) + MA(c, 2 * n5) + MA(c, 4 * n5)) / 3
|
||
PBX6 = (EMA(c, n6) + MA(c, 2 * n6) + MA(c, 4 * n6)) / 3
|
||
return pd.DataFrame(
|
||
{'PBX1': round(PBX1, 2), 'PBX2': round(PBX2, 2), 'PBX3': round(PBX3, 2),
|
||
'PBX4': round(PBX4, 2), 'PBX5': round(PBX5, 2), 'PBX6': round(PBX6, 2)}
|
||
)
|
||
|
||
|
||
def BOLL(close, N): # 布林线
|
||
boll = MA(close, N)
|
||
UB = boll + 2 * STD(close, N)
|
||
LB = boll - 2 * STD(close, N)
|
||
return pd.DataFrame({'BOLL': round(boll, 2), 'UB': round(UB, 2), 'LB': round(LB, 2)})
|
||
|
||
|
||
def ROC(close, n, m):
|
||
"""
|
||
变动率指标
|
||
:param close:
|
||
:param n:
|
||
:param m:
|
||
:return:
|
||
"""
|
||
c = close
|
||
roc = 100 * (c - REF(c, n)) / REF(c, n)
|
||
maroc = MA(roc, m)
|
||
return pd.DataFrame({'ROC': round(roc, 2), 'MAROC': round(maroc, 2)})
|
||
|
||
|
||
def MTM(close, n, m):
|
||
"""
|
||
动量线
|
||
:param close:
|
||
:param n:
|
||
:param m:
|
||
:return:
|
||
"""
|
||
c = close
|
||
mtm = c - REF(c, n)
|
||
mtm_ma = MA(mtm, m)
|
||
return pd.DataFrame({'MTM': round(mtm, 2), 'MTMMA': round(mtm_ma, 2)})
|
||
|
||
|
||
def MFI(close, high, low, vol, n):
|
||
"""
|
||
资金指标
|
||
:param close:
|
||
:param high:
|
||
:param low:
|
||
:param vol:
|
||
:param n:
|
||
:return:
|
||
"""
|
||
c, h, l, v = close, high, low, vol
|
||
TYP = (c + h + l) / 3
|
||
V1 = SUM(IF(TYP > REF(TYP, 1), TYP * v, 0), n) / \
|
||
SUM(IF(TYP < REF(TYP, 1), TYP * v, 0), n)
|
||
mfi = 100 - (100 / (1 + V1))
|
||
return pd.DataFrame({'MFI': round(mfi, 2)})
|
||
|
||
|
||
def SKDJ(close, high, low, N, M):
|
||
c = close
|
||
LOWV = LLV(low, N)
|
||
HIGHV = HHV(high, N)
|
||
RSV = EMA((c - LOWV) / (HIGHV - LOWV) * 100, M)
|
||
K = EMA(RSV, M)
|
||
D = MA(K, M)
|
||
return pd.DataFrame({'SKDJ_K': round(K, 2), 'SKDJ_D': round(D, 2)})
|
||
|
||
|
||
def WR(close, high, low, N, N1):
|
||
"""
|
||
威廉指标
|
||
:param close:
|
||
:param high:
|
||
:param low:
|
||
:param N:
|
||
:param N1:
|
||
:return:
|
||
"""
|
||
c, h, l = close, high, low
|
||
WR1 = round(100 * (HHV(h, N) - c) / (HHV(h, N) - LLV(l, N)), 2)
|
||
WR2 = round(100 * (HHV(h, N1) - c) / (HHV(h, N1) - LLV(l, N1)), 2)
|
||
return pd.DataFrame({'WR1': round(WR1, 2), 'WR2': round(WR2, 2)})
|
||
|
||
|
||
def BIAS(DF, N1, N2, N3): # 乖离率
|
||
CLOSE = DF
|
||
BIAS1 = (CLOSE - MA(CLOSE, N1)) / MA(CLOSE, N1) * 100
|
||
BIAS2 = (CLOSE - MA(CLOSE, N2)) / MA(CLOSE, N2) * 100
|
||
BIAS3 = (CLOSE - MA(CLOSE, N3)) / MA(CLOSE, N3) * 100
|
||
DICT = {'BIAS1': BIAS1, 'BIAS2': BIAS2, 'BIAS3': BIAS3}
|
||
VAR = pd.DataFrame(DICT)
|
||
return VAR
|
||
|
||
|
||
def RSI(c, N1, N2, N3): # 相对强弱指标RSI1:SMA(MAX(CLOSE-LC,0),N1,1)/SMA(ABS(CLOSE-LC),N1,1)*100;
|
||
DIF = c - REF(c, 1)
|
||
RSI1 = round((SMA(MAX(DIF, 0), N1) / round(SMA(ABS(DIF), N1) * 100, 3)) * 10000, 2)
|
||
RSI2 = round((SMA(MAX(DIF, 0), N2) / round(SMA(ABS(DIF), N2) * 100, 3)) * 10000, 2)
|
||
RSI3 = round((SMA(MAX(DIF, 0), N3) / round(SMA(ABS(DIF), N3) * 100, 3)) * 10000, 2)
|
||
return pd.DataFrame({'RSI1': RSI1, 'RSI2': RSI2, 'RSI3': RSI3})
|
||
|
||
|
||
def ADTM(DF, N, M): # 动态买卖气指标
|
||
HIGH = DF['high']
|
||
LOW = DF['low']
|
||
OPEN = DF['open']
|
||
DTM = IF(OPEN <= REF(OPEN, 1), 0, MAX(
|
||
(HIGH - OPEN), (OPEN - REF(OPEN, 1))))
|
||
DBM = IF(OPEN >= REF(OPEN, 1), 0, MAX((OPEN - LOW), (OPEN - REF(OPEN, 1))))
|
||
STM = SUM(DTM, N)
|
||
SBM = SUM(DBM, N)
|
||
ADTM1 = IF(STM > SBM, (STM - SBM) / STM,
|
||
IF(STM == SBM, 0, (STM - SBM) / SBM))
|
||
MAADTM = MA(ADTM1, M)
|
||
DICT = {'ADTM': ADTM1, 'MAADTM': MAADTM}
|
||
VAR = pd.DataFrame(DICT)
|
||
return VAR
|
||
|
||
|
||
def DDI(DF, N, N1, M, M1): # 方向标准离差指数
|
||
H = DF['high']
|
||
L = DF['low']
|
||
DMZ = IF((H + L) <= (REF(H, 1) + REF(L, 1)), 0,
|
||
MAX(ABS(H - REF(H, 1)), ABS(L - REF(L, 1))))
|
||
DMF = IF((H + L) >= (REF(H, 1) + REF(L, 1)), 0,
|
||
MAX(ABS(H - REF(H, 1)), ABS(L - REF(L, 1))))
|
||
DIZ = SUM(DMZ, N) / (SUM(DMZ, N) + SUM(DMF, N))
|
||
DIF = SUM(DMF, N) / (SUM(DMF, N) + SUM(DMZ, N))
|
||
ddi = DIZ - DIF
|
||
ADDI = SMA(ddi, N1, M)
|
||
AD = MA(ADDI, M1)
|
||
DICT = {'DDI': ddi, 'ADDI': ADDI, 'AD': AD}
|
||
VAR = pd.DataFrame(DICT)
|
||
return VAR
|
||
|
||
|
||
ZIG_STATE_START = 0
|
||
ZIG_STATE_RISE = 1
|
||
ZIG_STATE_FALL = 2
|
||
|
||
|
||
def ZIG(d, k, n):
|
||
"""
|
||
之字转向指标,当前价格变化超过 x% 时候变化
|
||
:param d: 交易日期
|
||
:param k: 价格
|
||
:param n: 系数
|
||
:return:
|
||
"""
|
||
x = round(n / 100, 2)
|
||
peer_i = 0
|
||
candidate_i = None
|
||
scan_i = 0
|
||
peers = [0]
|
||
z = np.zeros(len(k))
|
||
state = ZIG_STATE_START
|
||
while True:
|
||
scan_i += 1
|
||
if scan_i == len(k) - 1:
|
||
# 扫描到尾部
|
||
if candidate_i is None:
|
||
peer_i = scan_i
|
||
peers.append(peer_i)
|
||
else:
|
||
if state == ZIG_STATE_RISE:
|
||
if k[scan_i] >= k[candidate_i]:
|
||
print(d[scan_i], "1 --->>>", d[candidate_i])
|
||
peer_i = scan_i
|
||
peers.append(peer_i)
|
||
else:
|
||
peer_i = candidate_i
|
||
peers.append(peer_i)
|
||
peer_i = scan_i
|
||
peers.append(peer_i)
|
||
elif state == ZIG_STATE_FALL:
|
||
if k[scan_i] <= k[candidate_i]:
|
||
print(d[scan_i], "2 --->>>", d[candidate_i])
|
||
peer_i = scan_i
|
||
peers.append(peer_i)
|
||
else:
|
||
peer_i = candidate_i
|
||
peers.append(peer_i)
|
||
peer_i = scan_i
|
||
peers.append(peer_i)
|
||
break
|
||
if state == ZIG_STATE_START:
|
||
if k[scan_i] >= k[peer_i] * (1 + x):
|
||
print(d[scan_i], "3 --->>>", d[peer_i])
|
||
candidate_i = scan_i
|
||
state = ZIG_STATE_RISE
|
||
elif k[scan_i] <= k[peer_i] * (1 - x):
|
||
print(d[scan_i], "4 --->>>", d[peer_i])
|
||
candidate_i = scan_i
|
||
state = ZIG_STATE_FALL
|
||
elif state == ZIG_STATE_RISE:
|
||
if k[scan_i] >= k[candidate_i]:
|
||
candidate_i = scan_i
|
||
elif k[scan_i] <= k[candidate_i] * (1 - x):
|
||
print(d[scan_i], "5 --->>>", d[candidate_i])
|
||
peer_i = candidate_i
|
||
peers.append(peer_i)
|
||
state = ZIG_STATE_FALL
|
||
candidate_i = scan_i
|
||
elif state == ZIG_STATE_FALL:
|
||
if k[scan_i] <= k[candidate_i]:
|
||
print(d[scan_i], "6 --->>>", d[candidate_i])
|
||
candidate_i = scan_i
|
||
elif k[scan_i] >= k[candidate_i] * (1 + x):
|
||
print(d[scan_i], "7 --->>>", d[candidate_i])
|
||
peer_i = candidate_i
|
||
peers.append(peer_i)
|
||
state = ZIG_STATE_RISE
|
||
candidate_i = scan_i
|
||
for i in range(len(peers) - 1):
|
||
peer_start_i = peers[i]
|
||
peer_end_i = peers[i + 1]
|
||
start_value = k[peer_start_i]
|
||
end_value = k[peer_end_i]
|
||
a = (end_value - start_value) / (peer_end_i - peer_start_i) # 斜率
|
||
for j in range(peer_end_i - peer_start_i + 1):
|
||
z[j + peer_start_i] = start_value + a * j
|
||
return pd.Series(z), peers
|
||
|
||
|
||
def TROUGHBARS(z, p, m):
|
||
"""
|
||
前 m 个 zig 波谷到当前的距离
|
||
:param z: zig 指标
|
||
:param p: zip 转折点
|
||
:param m: 系数
|
||
:return:
|
||
"""
|
||
trough_bars = np.zeros(len(z))
|
||
if len(z) > 3:
|
||
j = 1
|
||
# 判断第一个是谷还是峰 ,峰则取偶数,如果是谷,则取奇数
|
||
if z[0] > z[1]:
|
||
# 第一个是波谷
|
||
for i in range(len(p)):
|
||
peer = p[i]
|
||
j = i + m * 2
|
||
if 0 < i and len(p) > j and i % 2 == 1:
|
||
num = p[j] - peer - 1
|
||
trough_bars[p[j] - 1] = num
|
||
trough_bars[p[j]] = 1
|
||
if z[0] < z[1]:
|
||
# 第一个是波峰
|
||
for i in range(len(p)):
|
||
peer = p[i]
|
||
j = i + m * 2
|
||
if 0 < i and len(p) > j and i % 2 == 0:
|
||
num = p[j] - peer - 1
|
||
trough_bars[p[j] - 1] = num
|
||
trough_bars[p[j]] = 1
|
||
return pd.Series(trough_bars)
|
||
|
||
|
||
def CROSS(a, b):
|
||
"""
|
||
穿越信号
|
||
当a向上穿越b时,标记1;当a向下穿越b时,标记-1;没穿越标记0
|
||
:param obj:
|
||
:param ref:
|
||
:return:
|
||
"""
|
||
assert len(a) == len(b), '穿越信号输入维度不相等'
|
||
assert len(a) > 1, '穿越信号长度至少为2'
|
||
res = np.zeros(len(a))
|
||
for i in range(len(a) - 2, -1, -1):
|
||
if a[i + 1] <= b[i + 1] and a[i] > b[i] and a[i + 1] < a[i]:
|
||
# 向上穿越时,标记1
|
||
res[i] = 1
|
||
elif a[i + 1] >= b[i + 1] and a[i] < b[i] and a[i + 1] > a[i]:
|
||
res[i] = -1
|
||
else:
|
||
res[i] = 0
|
||
# print(f"a+1 = {a[i + 1]}, b+1 = {b[i + 1]} , a = {a[i]} , b = {b[i]} , res = {res[i]}")
|
||
return pd.Series(res)
|
||
|
||
|
||
def _calc_slope(x):
|
||
return np.polyfit(range(len(x)), x, 1)[0]
|
||
|
||
|
||
def rolling_window(a, window):
|
||
shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
|
||
strides = a.values.strides + (a.values.strides[-1],)
|
||
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
|
||
|
||
|
||
def SLOPE(series, n):
|
||
"""
|
||
SLOPE(X,N) 返回线性回归斜率,N支持变量
|
||
参考:https://blog.csdn.net/luhouxiang/article/details/113816062
|
||
"""
|
||
a = rolling_window(series, n)
|
||
obj = np.array([_calc_slope(x) for x in a])
|
||
new_obj = np.pad(obj, (len(series) - len(obj), 0), 'constant', constant_values=(np.nan, np.nan))
|
||
return new_obj
|
||
|
||
|
||
def GOLD_MACD(df_data: pd.DataFrame):
|
||
"""
|
||
黄金MACD指标
|
||
:param df_data:
|
||
:return:
|
||
"""
|
||
df = df_data[::-1].reset_index(drop=True)
|
||
CLOSE = df["close"]
|
||
d = df["trade_date"]
|
||
MACD = (EMA(CLOSE, 30) - REF(EMA(CLOSE, 30), 1)) / REF(EMA(CLOSE, 30), 1) * 100
|
||
DIF = EMA(SUM(MACD, 2), 5)
|
||
buy_1 = DIF > REF(DIF, 1)
|
||
buy_2 = DIF < REF(DIF, 1)
|
||
|
||
DEA = MA(DIF, 5)
|
||
return pd.DataFrame(
|
||
{'code': df['ts_code'], 'date': d, 'MACD': MACD, 'DIF': DIF, 'DEA': DEA, 'buy1': buy_1, "buy2": buy_2})
|
||
|
||
|
||
def DJCPX(df_data: pd.DataFrame):
|
||
"""
|
||
顶级操盘线 指标
|
||
:param df_data:
|
||
:return:
|
||
"""
|
||
df = df_data[::-1].reset_index(drop=True)
|
||
k = df["close"]
|
||
d = df["trade_date"]
|
||
# print(f'{d[i]} -->> {buy_1[i]} -->> {buy_2[i]} -->> {B[i]}')
|
||
VAR_200 = round((100 - ((90 * (HHV(df["high"], 20) - df["close"])) / (
|
||
HHV(df["high"], 20) - LLV(df["low"], 20)))), 2)
|
||
VAR_300 = round((100 - MA(
|
||
((100 * (HHV(df["high"], 5) - df["close"])) / (HHV(df["high"], 5) - LLV(df["low"], 5))),
|
||
34)), 2)
|
||
VAR_300_MA_5 = MA(VAR_300, 5)
|
||
# F:IF(CROSS(VAR200,MA(VAR300,5)),LOW * 0.98,DRAWNULL),CROSSDOT,LINETHICK3,COLORFF00FF;
|
||
# CROSS 上穿函数 CROSS(A,B)表示当A从下方向上穿过B时返回1,否则返回0
|
||
F = np.zeros(df.shape[0])
|
||
VAR_CROSS = CROSS(VAR_200, VAR_300_MA_5)
|
||
for i in range(df.shape[0]):
|
||
if VAR_CROSS[i] == 1:
|
||
F[i] = round(df["low"][i] * 0.98, 2)
|
||
# 重心:=(C+0.618*REF(C,1)+0.382*REF(C,1)+0.236*REF(C,3)+0.146*REF(C,4))/2.382;
|
||
ZX = round((k + (0.618 * REF(k, 1)) + (0.382 * REF(k, 1)) + (0.236 * REF(k, 3)) + (
|
||
0.146 * REF(k, 4))) / 2.382, 2)
|
||
# 【操盘线】:EMA(((SLOPE(C,22)*20)+C),55),COLORYELLOW,LINETHICK4;
|
||
CPX = round(EMA(((SLOPE(k, 22) * 20) + k), 55), 2)
|
||
# 【黄金线】:IF(重心>=【操盘线】,【操盘线】,DRAWNULL),COLORRED,LINETHICK2;
|
||
HJX = np.zeros(df.shape[0])
|
||
# 【空仓线】:IF(重心<【操盘线】,【操盘线】,DRAWNULL),COLORCYAN,LINETHICK2;
|
||
KCX = np.zeros(df.shape[0])
|
||
for i in range(df.shape[0]):
|
||
if ZX[i] >= CPX[i]:
|
||
HJX[i] = CPX[i]
|
||
else:
|
||
KCX[i] = CPX[i]
|
||
return pd.DataFrame(
|
||
{'code': df['ts_code'], 'date': d, 'F': F, '黄金线': HJX, '空仓线': KCX})
|
||
|
||
|
||
def CCI(DF, n: int = 14):
|
||
TP = (DF['low'] + DF['high'] + DF['close']) / 3
|
||
MA = TP.rolling(window=n).mean()
|
||
MD = TP.rolling(window=n).apply(lambda x: abs(x - x.mean()).mean(), raw=False)
|
||
return round((TP - MA) / (0.015 * MD), 2)
|
||
|
||
|
||
def bullish(DF, N):
|
||
"""
|
||
多头指标,N项的递增序列
|
||
:param DF:
|
||
:param N:
|
||
:return:
|
||
"""
|
||
return pd.Series.rolling(DF, N).apply(lambda x: x.is_monotonic_increasing)
|
||
|
||
|
||
def bearish(DF, N):
|
||
"""
|
||
空头指标,N项的递减序列
|
||
:param DF:
|
||
:param N:
|
||
:return:
|
||
"""
|
||
return pd.Series.rolling(DF, N).apply(lambda x: x.is_monotonic_decreasing)
|
||
|
||
|
||
def OBV(c, v, M):
|
||
# diff 计算相邻元素的差值
|
||
change = np.diff(c)
|
||
# sign 用于获取数组元素的符号的函数,对于正数,返回 1,对于负数,返回 -1,对于零,返回 0
|
||
# hstack 用于水平(按列)连接数组的函数
|
||
sig = np.hstack([[1], np.sign(change)])
|
||
# cumsum 计算累积和的方法。它将给定数组中的元素逐个累加
|
||
obv_ = np.cumsum(v * sig)
|
||
OBV = pd.Series(obv_)
|
||
MAOBV = MA(OBV, M)
|
||
return pd.DataFrame({'OBV': OBV, 'MAOBV': MAOBV})
|
||
|
||
|
||
def OBV_PLUS(DF, M):
|
||
"""
|
||
OBV策略升级:TODO 还没完成
|
||
1. 增加价格相距大的那一天成交量的权重,这可以更突出上升趋势和下降趋势。
|
||
2. 当天的成交量以一定比例加入OBV中,而不是将全天的成交量全部加入OBV中。
|
||
:param DF:
|
||
:param M:
|
||
:return:
|
||
"""
|
||
CLOSE = DF['close']
|
||
VOL = DF['vol']
|
||
ref = REF(CLOSE, 1)
|
||
var_total = 0
|
||
for index, row in DF.iterrows():
|
||
if np.isnan(ref[index]):
|
||
var_total += VOL[index]
|
||
continue
|
||
if row["close"] > ref[index]:
|
||
vol = VOL[index] * 1
|
||
elif row["close"] == ref[index]:
|
||
vol = 0
|
||
else:
|
||
vol = VOL[index] * -1
|
||
var_total += vol
|
||
|
||
|
||
def ASI(OPEN, CLOSE, HIGH, LOW, M1=26, M2=10):
|
||
"""
|
||
# 振动升降指标
|
||
:param OPEN:
|
||
:param CLOSE:
|
||
:param HIGH:
|
||
:param LOW:
|
||
:param M1:
|
||
:param M2:
|
||
:return:
|
||
"""
|
||
LC = REF(CLOSE, 1)
|
||
AA = ABS(HIGH - LC)
|
||
BB = ABS(LOW - LC)
|
||
CC = ABS(HIGH - REF(LOW, 1))
|
||
DD = ABS(LC - REF(OPEN, 1))
|
||
R = IF((AA > BB) & (AA > CC), AA + BB / 2 + DD / 4, IF((BB > CC) & (BB > AA), BB + AA / 2 + DD / 4, CC + DD / 4))
|
||
X = (CLOSE - LC + (CLOSE - OPEN) / 2 + LC - REF(OPEN, 1))
|
||
SI = 16 * X / R * MAX(AA, BB)
|
||
ASI = SUM(SI, M1)
|
||
ASIT = MA(ASI, M2)
|
||
return {'ASI': ASI, 'ASIT': ASIT}
|
||
|
||
|
||
def DMI(CLOSE, HIGH, LOW, M1=14, M2=6): # 动向指标:结果和同花顺,通达信完全一致
|
||
TR = SUM(MAX(MAX(HIGH - LOW, ABS(HIGH - REF(CLOSE, 1))), ABS(LOW - REF(CLOSE, 1))), M1)
|
||
HD = HIGH - REF(HIGH, 1)
|
||
LD = REF(LOW, 1) - LOW
|
||
DMP = SUM(IF((HD > 0) & (HD > LD), HD, 0), M1)
|
||
DMM = SUM(IF((LD > 0) & (LD > HD), LD, 0), M1)
|
||
PDI = (DMP * 100) / TR
|
||
MDI = (DMM * 100) / TR
|
||
ADX = MA(ABS(MDI - PDI) / (PDI + MDI) * 100, M2)
|
||
ADXR = (ADX + REF(ADX, M2)) / 2
|
||
return {'PDI': round(PDI.fillna(0), 2), 'MDI': round(MDI.fillna(0), 2), 'ADX': round(ADX.fillna(0), 2),
|
||
'ADXR': round(ADXR.fillna(0), 2)}
|
||
|
||
|
||
def RM_KDJ(C, H, L, N, M1, M2):
|
||
RSV = (C - LLV(L, N)) / (HHV(H, N) - LLV(L, N)) * 100
|
||
K = RM_SMA(RSV, M1, 1)
|
||
D = RM_SMA(K, M2, 1)
|
||
J = 3 * K - 2 * D
|
||
return pd.DataFrame({'KDJ_K': round(K, 2), 'KDJ_D': round(D, 2), 'KDJ_J': round(J, 2)})
|
||
|
||
|
||
def INTPART(number):
|
||
number = number.fillna(0)
|
||
return number.astype(int)
|
||
|
||
|
||
def JXNH(CLOSE, OPEN, VOL):
|
||
VAR1 = MA(CLOSE, 5)
|
||
VAR2 = MA(CLOSE, 10)
|
||
VAR3 = MA(CLOSE, 30)
|
||
VARB = SUM(CLOSE * VOL * 100, 28) / SUM(VOL * 100, 28)
|
||
VARC = INTPART(VARB * 100) / 100
|
||
VARD = EMA(CLOSE, 5) - EMA(CLOSE, 10)
|
||
VARE = EMA(VARD, 9)
|
||
VAR13 = REF(VARE, 1)
|
||
VAR14 = VARE
|
||
VAR15 = VAR14 - VAR13
|
||
VAR16 = REF(VARD, 1)
|
||
VAR17 = VARD
|
||
VAR18 = VAR17 - VAR16
|
||
VAR19 = OPEN
|
||
VAR1A = CLOSE
|
||
JXNH = (VAR19 <= VAR1) & \
|
||
(VAR19 <= VAR2) & \
|
||
(VAR19 <= VAR3) & \
|
||
(VAR1A >= VAR1) & \
|
||
(VAR1A >= VARC) & (VAR15 > 0) & (VAR18 > 0)
|
||
return pd.DataFrame({'JXNH': JXNH})
|