LoginSignup
0
1

More than 3 years have passed since last update.

HLバンドを順張りで使ってみる

Last updated at Posted at 2020-02-13

はじめに

今回はHL (HighLow) バンドを用いたアルゴリズムを作ってみました.
HLバンドの詳細については以下の記事を参考にしたのでご覧ください.

HLバンドの見方・使い方【テクニカル指標・トレンド系】

簡単に説明すると, HLバンドではある期間の高値の最大値を結んだ線(Highバンド)と, 安値の最小値を結んだ線(Lowバンド), 2本の線の平均線(Middleバンド)を用いています.

では早速本題に移ります.

HLバンドアルゴリズム

シグナル

買いシグナル:Middleバンドを終値(cp)が突き抜けたとき
売りシグナル:Middleバンドを終値(cp)が下回ったとき or 終値がHighバンドを突き抜けたとき

シグナルの決定はこちらを参考にしました.

コード

今回のコードはこちら

#HLバンド
import maron
import maron.signalfunc as sf
import maron.execfunc as ef
import pandas as pd
import talib as ta 
import numpy as np 

#ot = maron.OrderType.MARKET_CLOSE # シグナルがでた翌日の終値のタイミングでオーダー
ot = maron.OrderType.MARKET_OPEN   # シグナルがでた翌日の始値のタイミングでオーダー
#ot = maron.OrderType.LIMIT        # 指値によるオーダー

def initialize(ctx):
  # 設定
  ctx.logger.debug("initialize() called")
  ctx.configure(
    channels={               # 利用チャンネル
      "jp.stock": {
        "symbols": [
          "jp.stock.2914",
          "jp.stock.3382", 
          "jp.stock.4063", 
          "jp.stock.4452",
          "jp.stock.4502",
          "jp.stock.4503",
          "jp.stock.4568",
          "jp.stock.6094",
          "jp.stock.6501",
          "jp.stock.6758",
          "jp.stock.6861",
          "jp.stock.6954",
          "jp.stock.6981",
          "jp.stock.7203",
          "jp.stock.7267",
          "jp.stock.7751",
          "jp.stock.7974",
          "jp.stock.8031",
          "jp.stock.8058",
          "jp.stock.8306",
          "jp.stock.8316",
          "jp.stock.8411",
          "jp.stock.8766",
          "jp.stock.8802",
          "jp.stock.9020",
          "jp.stock.9022",
          "jp.stock.9432",
          "jp.stock.9433",
          "jp.stock.9437",
          "jp.stock.9984",

        ],
        "columns": [
          "close_price",     # 終値
          "close_price_adj", # 終値(株式分割調整後)
          "high_price_adj",    # 高値(株式分割調整後)
          "low_price_adj",     # 安値(株式分割調整後)
          "volume_adj",     # 出来高
          "txn_volume",     # 売買代金
        ]
      }
    }
  )

  # シグナル定義
  def _my_signal(data):
    cp =  data["close_price_adj"].fillna(method='ffill')  #終値取得
    hp = data["high_price_adj"].fillna(method='ffill')    #高値取得
    lp = data["low_price_adj"].fillna(method='ffill')     #安値取得
    hband = hp.rolling(20).max()                          #Highバンド設定
    lband = lp.rolling(20).min()                          #Lowバンド設定
    mband = (hband - lband)/2 + lband                     #Middleバンド設定

    market_sig = pd.DataFrame(data=0.0, columns=cp.columns, index=cp.index)
    buy_sig = ((mband.shift(1) > cp.shift(1)) & (mband < cp))
    sell_sig = ((mband > cp) | (cp > hband))
    # buy_sigがTrueのとき1.0、sell_sigがTrueのとき-1.0とおく
    market_sig[buy_sig == True] = 1.0
    market_sig[sell_sig == True] = -1.0
    market_sig[(buy_sig == True) & (sell_sig == True)] = 0.0
    #ctx.logger.debug(market_sig)

    return {
      # "hband:g2": hband,
      # "lband:g2": lband,
      # "mband:g2": mband,
      "hband": hband,
      "lband": lband,
      "mband": mband,
      "market:sig": market_sig,
    }

  # シグナル登録
  ctx.regist_signal("my_signal", _my_signal)

def handle_signals(ctx, date, current):
  '''
  current: pd.DataFrame
  '''
  market_sig = current["market:sig"]

  done_syms = set([])

  # 損切り、利確の設定
  for (sym, val) in ctx.portfolio.positions.items():
    returns = val["returns"]
    if returns < -0.02:
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="損切り(%f)" % returns)
      done_syms.add(sym)
    elif returns > 0.04:
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
      done_syms.add(sym)

  # 買いシグナル
  buy = market_sig[market_sig > 0.0]
  for (sym, val) in buy.items():
    if sym in done_syms:
      continue

    sec = ctx.getSecurity(sym)
    sec.order(sec.unit() * 1, orderType=ot, comment="SIGNAL BUY")
    #ctx.logger.debug("BUY: %s,  %f" % (sec.code(), val))
    pass

  # # 売りシグナル
  sell = market_sig[market_sig < 0.0]
  for (sym, val) in sell.items():
    if sym in done_syms:
      continue
    sec = ctx.getSecurity(sym)
    sec.order(sec.unit() * -1, orderType=ot, comment="SIGNAL SELL")
    #ctx.logger.debug("SELL: %s,  %f" % (sec.code(), val))
    pass

コード解説

基本的なコードの解説は, 勉強会用に作成した資料が下記のリンク先にあるのでこちらをご覧ください.

今回重要なところを解説していきます.

69~71行目

    hband = hp.rolling(20).max()                          #Highバンド設定
    lband = lp.rolling(20).min()                          #Lowバンド設定
    mband = (hband - lband)/2 + lband                     #Middleバンド設定

ここでは, 各バンドの設定をしています. hbandは過去20日間の高値(cp)の最大値, lbandは過去20日間の安値(lp)の最小値, mbandはhbandとlbandの平均をとっています.

rollingについての詳しいことはこちら

74~75行目

    buy_sig = ((mband.shift(1) > cp.shift(1)) & (mband < cp))
    sell_sig = ((mband > cp) | (cp > hband))

買いシグナル:mbandを終値(cp)が突き抜けたとき
売りシグナル:mbandを終値(cp)が下回ったとき or 終値がhbandを突き抜けたとき

バックテスト結果

hlband2.PNG

3年で損益率が17%,,,,

あまり儲かっていませんね.

MaxDrawdown, SharpRatio, αの値を見ても, かなり改善の余地がありそうです.

感想

HLバンドは一般的には, ブレイクアウト手法で使われることが多く, 大相場(普段と比べて, 株式相場全体が活況に満ちて高騰し, 出来高も大きく膨らんだ相場のこと)でないと失速することが多いため, すべての状況でHLバンドを用いてもあまり良いアルゴリズムはできないことが結果からも言えます.

免責注意事項

本コードを用いた実際のトレードで生じる損害は一切保証しかねますので、ご注意ください。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1