#今回やったこと
投資アルゴリズム開発プラットフォーム「QuantX」で、平均足を実装しました。
#平均足とは
株式投資の基本にローソク足チャートがありますが、ローソク足はわずかな株価の上下でも頻繁に陽線と陰線が入れ替わるため、ダマシも多くなりトレンドがやや読みにくいと言えます。
この点を改良したものが平均足です。平均足は、陽線(または陰線)が連続しやすいという特徴があり、トレンドの転換を判断しやすいと言えます。
平均足では、個々のローソク足の四本値として、実際の株価をそのまま使わずに、手を加えた値を使います。通常のローソク足の始値/高値/安値/終値をそれぞれCO/CH/CL/CC
で表し、平均足の始値/高値/安値/終値をそれぞれHO/HH/HL/HCで
表すとすると、以下のように表されます。
$HO = (1本前のHO+1本前のHC)/2$
$HC = (CO+CH+CL+CC)/4$
$HO = HO/HC/CHの最大値$
$HO = HO/HC/CLの最小値$
ただし、チャートの先頭では、1本前のデータがないのでHOは計算できず、2本目から計算します。また、2本目のHOでは、1本前のHOが決まっていないので、上の計算式の代わりに、1本前のローソク足のCO/CH/CL/CCの合計を4で割った値にします。
#アルゴリズム
今回書いたアルゴリズムはこちら
import pandas as pd
import numpy as np
def initialize(ctx):
# 設定
ctx.logger.debug("initialize() called")
ctx.configure(
channels={ # 利用チャンネル
"jp.stock": {
"symbols": [
"jp.stock.1305",
"jp.stock.9984",
"jp.stock.9983",
"jp.stock.7201",
"jp.stock.9201",
"jp.stock.9202",
"jp.stock.7203"
],
"columns": [
"open_price_adj", # 始値(株式分割調整後)
"high_price_adj", # 高値(株式分割調整後)
"low_price_adj", # 安値(株式分割調整後)
"close_price_adj", # 終値(株式分割調整後)
]
}
}
)
def HA(data):
op=data['open_price_adj'].fillna(method='ffill')
hp=data['high_price_adj'].fillna(method='ffill')
lp=data['low_price_adj'].fillna(method='ffill')
cp=data['close_price_adj'].fillna(method='ffill')
HA_Close=pd.DataFrame(index=cp.index, columns=cp.columns)
HA_Open=pd.DataFrame(index=cp.index, columns=cp.columns)
HA_High=pd.DataFrame(index=cp.index, columns=cp.columns)
HA_Low=pd.DataFrame(index=cp.index, columns=cp.columns)
HA_Close=(data['open_price_adj']+ data['high_price_adj']+ data['low_price_adj']+data['close_price_adj'])/4
for i in range(0, len(HA_Close)):
if i == 0:
HA_Open.iloc[i,:] = 0.0
elif i == 1:
HA_Open.iloc[i,:] = HA_Close.iloc[i-1, :]
else:
HA_Open.iloc[i,:] = (HA_Open.iloc[i-1, :] + HA_Close.iloc[i-1, :]) / 2
for (sym,val) in cp.items():
for i in range(0, len(HA_High)):
HA_High[sym][i] = np.max(np.array([HA_Open[sym][i], HA_Close[sym][i], hp[sym][i]]))
HA_Low[sym][i] = np.min(np.array([HA_Open[sym][i], HA_Close[sym][i], lp[sym][i]]))
return HA_Open, HA_High, HA_Low, HA_Close
def _my_signal(data):
HA_Open, HA_High, HA_Low, HA_Close = HA(data)
rosokuashi = HA_Close - HA_Open
buy_sig = (rosokuashi > 0) & (rosokuashi.shift(1) < 0)
sell_sig = (rosokuashi < 0) & (rosokuashi.shift(1) > 0)
return {
'buy:sig':buy_sig,
'sell:sig':sell_sig,
}
# シグナル登録
ctx.regist_signal("my_signal", _my_signal)
def handle_signals(ctx, date, current):
'''
current: pd.DataFrame
'''
df = current.copy()
done_syms = set([])
for (sym,val) in ctx.portfolio.positions.items():
returns = val["returns"]
if returns < -0.03:
sec = ctx.getSecurity(sym)
sec.order(-val["amount"], comment="損切り(%f)" % returns)
done_syms.add(sym)
elif returns > 0.05:
sec = ctx.getSecurity(sym)
sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
done_syms.add(sym)
# 買いシグナル
df_long = df[df["buy:sig"]]
if not df_long.empty:
for (sym, val) in df_long.iterrows():
if sym in done_syms:
continue
sec = ctx.getSecurity(sym)
msg = "買いシグナル"
sec.order(sec.unit() * 1, comment="SIGNAL BUY")
# 売りシグナル
df_sell = df[df["sell:sig"]]
if not df_sell.empty:
for (sym, val) in df_sell.iterrows():
if sym in done_syms:
continue
sec = ctx.getSecurity(sym)
msg = "売りシグナル"
sec.order(sec.unit() * -1, comment="SIGNAL SELL")
今回のエントリーは、陰線から陽線に変わったタイミングで買い、陽線から陰線に変わったタイミングで売り、という方法を採用しています、
平均足は、陽線と陰線が通常のローソク足に比べて続きやすいものの、株価が短期間で上下する場合には陽線と頻繁が頻繁に入れ替わるため、まだダマシがそこそこ多くなります。そのため、その他のテクニカル指標と併用することが求められるようです。