4
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Organization

QuantX FactoryでMACDのアルゴリズムを作ってみよう。

注)新バージョンの以降に伴い内容を大幅に変更しました。

本記事の内容

QuantXというプラットフォームを用い、MACDという金融指標を使った、投資アルゴリズムの作成を行います。

QuantX Factoryとは

URL:QuantX Factory ホームページ
開いてみるとこんな画面が出てきます。
スクリーンショット 2018-11-28 18.14.48.png

QuantX Factoryとは
ブラウザ上で動かせる、株式や仮想通貨などの売買ルール(アルゴリズム)の作成、販売ができるシステムトレードプラットフォームです。pythonというプログラミング言語を用いて動かします。

開発デモを体験するというボタンをクリックするとログインしてくださいという画面がでます。
Facebook,Googleアカウントなどで簡単にログインできるのでログインしちゃいましょう!

ログインが終わると何やら難しそうなコードが出てきます。スクリーンショット 2018-11-29 9.22.17.png

これは移動平均線という金融指標を用いたアルゴリズムです。
デフォルトですでに完成されています!

移動平均線について知りたい方はコチラ

Pythonでコードをいじり、バックテストをすることで株式売買のシミュレーションができちゃいます!!

指標の意味・役割の解説

MACDとは

MACDとは、「Moving Average Convergence Divergence」を略したもので、「マクディー」もしくは「エムエーシーディー」と呼ばれています。(自分は「マクディー」派)
MACDは移動平均線を進化させて、より精度の高い分析を行うために開発されたテクニカル分析です。

MACDの計算方法

単純移動平均と指数平滑移動平均の違い

MACDは単純移動平均とは異なり、指数平滑移動平均というもの用います。
単純移動平均と指数平滑移動平均のそれぞれの計算式の例は以下のようになります。

単純移動平均=(1日目の終値+2日目の終値+3日目の終値)/3日間
指数平滑移動平均=(1日目の終値+2日目の終値+3日目の終値×2)/3日間+1日

式をみるとわかると思いますが、最終日の終値を2倍で計算するため、最新の株価の値が大きく反映されやすくなっています。そのため、単純移動平均では実際の相場と少し遅れて形状が変動しますが、指数平滑移動平均だと実際の値動きに近い形で平均値が算出できるというわけです。

MACDの計算式

MACDは、期間の短い指数平滑移動平均である短期平均と、期間の長い指数平滑移動平均である長期平均を用いて、短期平均から長期平均の値を引いた差で求められます。

MACD=短期平均-長期平均
シグナル=MACDの単純移動平均線

一般的には短期平均の期間が12日、長期平均の期間が26日で、シグナルの平均期間は9日を利用する場合が多いです。
今回はPythonのTa-Libというライブラリーを使うので初心者の方は計算方法ガン無視でも大丈夫です!!

MACDの売買サインは?

では、上記の数値がどのような値になった時に売り買いするといいのでしょうか?
ショーボンドホールディングス(株)の直近三ヶ月の値を例にとって見てみます。

スクリーンショット 2018-12-05 18.49.54.png

MACDを利用した売買ポイントの見極め方はとても単純です。

MACDがシグナルを下から上へクロスしたポイント(ゴールデンクロス)が買いサインとなり、反対にMACDがシグナルを上から下へクロスしたポイント(デッドクロス)は売りサインになります。

今回の例で行くと図の感じになります。
スクリーンショット 2018-12-06 15.17.16.png

このようなシグナルを出すアルゴリズムを今回は作っていきます!

ゼロからコードを書くのは大変そうですが、talibというライブラリを使用することで簡単に実装できます。

talibはMACDの他にもボリンジャーバンド、ストキャスティックなどのを含む150以上のテクニカル指標をカバーしている便利なライブラリです。
talibのドキュメント

ソースコード

QuantX Factory URL: https://factory.quantx.io/developer/aaf3c362decc426d899e48ee2e129fe5/coding
(QuantX Factoryの開発画面に飛びます)


MACDのサンプルコード
# Sample Algorithm
# ライブラリーのimport
# 必要ライブラリー
import maron
import maron.signalfunc as sf
import maron.execfunc as ef
# 追加ライブラリー
# 使用可能なライブラリに関しましては右画面のノートをご覧ください①
import pandas as pd
import talib as ta
import numpy as np

# オーダ方法(目的の注文方法に合わせて以下の2つの中から一つだけコメントアウトを外してください)
# オーダー方法に関しましては右画面のノートをご覧ください②
#ot = maron.OrderType.MARKET_CLOSE # シグナルがでた翌日の終値のタイミングでオーダー
ot = maron.OrderType.MARKET_OPEN   # シグナルがでた翌日の始値のタイミングでオーダー
#ot = maron.OrderType.LIMIT        # 指値によるオーダー

# 銘柄、columnsの取得
# 銘柄の指定に関しては右画面のノートをご覧ください③
# columnsの取得に関しては右画面のノートをご覧ください④
def initialize(ctx):
  # 設定
  ctx.logger.debug("initialize() called")
  ctx.configure(
    channels={               # 利用チャンネル
      "jp.stock": {
        "symbols": [
            "jp.stock.2914", #JT(日本たばこ産業)
            "jp.stock.8766", #東京海上ホールディングス
            "jp.stock.8031", #三井物産
            "jp.stock.8316", #三井住友フィナンシャルグループ
            "jp.stock.8411", #みずほフィナンシャルグループ
            "jp.stock.9437", #NTTドコモ
            "jp.stock.4502", #武田薬品工業
            "jp.stock.8058", #三菱商事
            "jp.stock.9433", #KDDI
            "jp.stock.9432", #日本電信電話
            "jp.stock.7267", #ホンダ(本田技研工業)
            "jp.stock.8306", #三菱UFJフィナンシャル・グループ
            "jp.stock.4503", #アステラス製薬
            "jp.stock.4063", #信越化学工業
            "jp.stock.7974", #任天堂
            "jp.stock.6981", #村田製作所
            "jp.stock.3382", #セブン&アイ・ホールディングス
            "jp.stock.9020", #東日本旅客鉄道
            "jp.stock.8802", #三菱地所
            "jp.stock.9022", #東海旅客鉄道
            "jp.stock.9984", #ソフトバンクグループ
            "jp.stock.6861", #キーエンス
            "jp.stock.6501", #日立製作所
            "jp.stock.6752", #パナソニック
            "jp.stock.6758", #ソニー
            "jp.stock.6954", #ファナック
            "jp.stock.7203", #トヨタ自動車
            "jp.stock.7751", #キヤノン
            "jp.stock.4452", #花王
            "jp.stock.6098", #リクルートホールディングス     
        ],
        "columns": [
          "close_price",     # 終値
          "close_price_adj", # 終値(株式分割調整後)
          #"volume_adj",     # 出来高
          #"txn_volume",     # 売買代金
        ]
      }
    }
  )

  # シグナル定義
  def _my_signal(data):
    #終値のデータを取得
    cp=data["close_price_adj"].fillna(method="ffill")

    syms = data.minor_axis   # 銘柄リストの作成
    dates = data.major_axis  # 日付リストの作成

    #データを格納する場所
    macd = pd.DataFrame(data=0.0, columns=syms, index=dates)
    macdsignal = pd.DataFrame(data=0.0, columns=syms, index=dates)
    macdhist = pd.DataFrame(data=0.0, columns=syms, index=dates)

    #TA-LibによるMACDの計算
    for (sym,val) in cp.items():
      macd[sym],macdsignal[sym],macdhist[sym] = ta.MACD(cp[sym],fastperiod=12,slowperiod=26,signalperiod=9)

    #売買シグナル生成部分
    buy_sig = (macd > macdsignal) & (macd.shift(1) < macdsignal.shift(1))
    sell_sig = (macd < macdsignal) & (macd.shift(1) > macdsignal.shift(1))

    #market_sigという全て0が格納されているデータフレームを作成
    market_sig = pd.DataFrame(data=0.0, columns=syms, index=dates)

    #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 {
      "MACD": macd, 
      "MACDSignal": macdsignal, 
      "MACDHist": macdhist, 
      "market:sig": market_sig,
    }

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

def handle_signals(ctx, date, current):  # 日ごとの処理部分
  '''
  current: pd.DataFrame
  '''
  # initializeの_my_signalで生成したシグナルをmarket_sigに格納
  market_sig = current["market:sig"]
  done_syms = set([])  # 利益確定及び損切りが行われた銘柄を格納するset型
  none_syms = set([])  # portfolio.positionsに存在しない銘柄を格納するset型
  # portfolio.positions(保有している銘柄)に対象銘柄(sym)が存在するかのチェック
  for (sym, val) in market_sig.items():
    if sym not in ctx.portfolio.positions:
      none_syms.add(sym)
  # portfolio.positions(保有している銘柄)のそれぞれの銘柄(sym)の保有株数が0ではないかのチェック
  for (sym, val) in ctx.portfolio.positions.items():
    if val["amount"] == 0:
      none_syms.add(sym)
  # 損切り、利益確定(利確)の設定
  # 所有している銘柄を1つずつ確認する繰り返し処理
  for (sym, val) in ctx.portfolio.positions.items():
    # 損益率の取得
    returns = val["returns"]
    if returns < -0.03:  # 損益率が-3%未満(絶対値で3%より大きい損)の場合
      # 損切りのための売り注文
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="損切り(%f)" % returns)
      # 利益確定及び損切りが行われた銘柄を格納するset型にsymに代入されている銘柄を追加
      done_syms.add(sym)
    elif returns > 0.05:  # 損益率が+5%より大きい場合
      # 利益確定(利確)のための売り注文
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
      # 利益確定及び損切りが行われた銘柄を格納するset型にsymに代入されている銘柄を追加
      done_syms.add(sym)
  buy = market_sig[market_sig > 0.0]  # 買いシグナル
  for (sym, val) in buy.items():  # 買いシグナルが出ている銘柄を1つずつ処理
    # done_symsまたはnone_symsにsymがある場合
    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))
  sell = market_sig[market_sig < 0.0]  # 売りシグナル
  for (sym, val) in sell.items():  # 売りシグナルが出ている銘柄を1つずつ処理
    # done_symsまたはnone_symsにsymがある場合
    if (sym in done_syms) | (sym in none_syms):
      continue  # 処理をスキップ
    # 売り注文
    sec = ctx.getSecurity(sym)
    sec.order(sec.unit() * -1,orderType=ot, comment="SIGNAL SELL")


コードの解説

準備(ライブラリのインポート・オーダー方法の設定)

※QuantX Factory tutorialの記事で共通している部分です。すでに理解している方は読み飛ばしていただいて結構です。

準備の解説
import maron
import pandas as pd
import talib as ta
import numpy as np 

# オーダ方法(目的の注文方法に合わせて以下の2つの中から一つだけコメントアウトを外して下さい)
# ot = maron.OrderType.MARKET_CLOSE  # シグナルが出たた翌日の終値のタイミングでオーダー
ot = maron.OrderType.MARKET_OPEN   # シグナルが出たた翌日の始値のタイミングでオーダー
# ot = maron.OrderType.LIMIT

細かくわけて説明します。

ライブラリのインポート

import maron
import pandas as pd
import talib as ta
import numpy as np 

このアルゴリズムでは、maronpandasnumpyをインポートします。
maronはバックテストを行うためのQuantX Factory独自のライブラリです。
pandasはデータ分析用のライブラリです。pandas
talibはテクニカル指標を簡単に計算してくれるライブラリです。templateには元から記述されていますが、本アルゴでは使用しません。
numpyはデータを計算をしやすくするためのものです。numpy

オーダー方法の設定

# オーダ方法(目的の注文方法に合わせて以下の2つの中から一つだけコメントアウトを外して下さい)
# ot = maron.OrderType.MARKET_CLOSE  # シグナルが出たた翌日の終値のタイミングでオーダー
ot = maron.OrderType.MARKET_OPEN   # シグナルが出たた翌日の始値のタイミングでオーダー
# ot = maron.OrderType.LIMIT

修正の可能性あり??作成中


initializeの解説

※QuantX Factory tutorialの記事で共通している部分です。すでに理解している方は読み飛ばしていただいて結構です。

initializeの解説

アルゴリズムを初期化し、設定する部分です。
def initialize(ctx):
    # 設定
    ctx.logger.debug("initialize() called")
    ctx.configure(
      target="jp.stock.daily",
      channels={          # 利用チャンネル
        "jp.stock": {
          "symbols": [
            "jp.stock.2914", #JT(日本たばこ産業)
            "jp.stock.8766", #東京海上ホールディングス
            "jp.stock.8031", #三井物産
            "jp.stock.8316", #三井住友フィナンシャルグループ
            "jp.stock.8411", #みずほフィナンシャルグループ
            "jp.stock.9437", #NTTドコモ
            "jp.stock.4502", #武田薬品工業
            "jp.stock.8058", #三菱商事
            "jp.stock.9433", #KDDI
            "jp.stock.9432", #日本電信電話
            "jp.stock.7267", #ホンダ(本田技研工業)
            "jp.stock.8306", #三菱UFJフィナンシャル・グループ
            "jp.stock.4503", #アステラス製薬
            "jp.stock.4063", #信越化学工業
            "jp.stock.7974", #任天堂
            "jp.stock.6981", #村田製作所
            "jp.stock.3382", #セブン&アイ・ホールディングス
            "jp.stock.9020", #東日本旅客鉄道
            "jp.stock.8802", #三菱地所
            "jp.stock.9022", #東海旅客鉄道
            "jp.stock.9984", #ソフトバンクグループ
            "jp.stock.6861", #キーエンス
            "jp.stock.6501", #日立製作所
            "jp.stock.6752", #パナソニック
            "jp.stock.6758", #ソニー
            "jp.stock.6954", #ファナック
            "jp.stock.7203", #トヨタ自動車
            "jp.stock.7751", #キヤノン
            "jp.stock.4452", #花王
            "jp.stock.6098", #リクルートホールディングス     
       ],
          "columns": [
            #"open_price_adj",    # 始値(株式分割調整後)
            #"high_price_adj",    # 高値(株式分割調整後)
            #"low_price_adj",     # 安値(株式分割調整後)
            #"volume_adj",         # 出来高
            #"txn_volume",         # 売買代金
            #"close_price",        # 終値
            "close_price_adj",    # 終値(株式分割調整後) 
          ]
        }
      }
    )

    '''
    ~~
    シグナルを定義する部分
    def _my_signals(data):
       return{}
    ~~
    '''
    # シグナル登録
    ctx.regist_signal("my_signal", _my_signal)

細かく分けて説明します。

ログの出力

ctx.logger.debug("initialize() called")

ログに、バックテストが始まったというメッセージを出力します。

使用するデータの設定

ctx.configure(
      target="jp.stock.daily",
      channels={          # 利用チャンネル
        "jp.stock": {
          "symbols": [],
          "columns": []
        }

アルゴで使用する銘柄、価格を設定します。決まり文句のようなもので、辞書channelsの、keyが "symbols"のvalueに、使用する銘柄のリスト、keyが "columns"のvalueに、使用する価格を指定します。
今回使用した銘柄はTOPIX core30を採用しました。

使用する銘柄の設定

"symbols": [
            "jp.stock.2914", #JT(日本たばこ産業)
            "jp.stock.8766", #東京海上ホールディングス
            "jp.stock.8031", #三井物産
            "jp.stock.8316", #三井住友フィナンシャルグループ
            "jp.stock.8411", #みずほフィナンシャルグループ
            "jp.stock.9437", #NTTドコモ
            "jp.stock.4502", #武田薬品工業
            "jp.stock.8058", #三菱商事
            "jp.stock.9433", #KDDI
            "jp.stock.9432", #日本電信電話
            "jp.stock.7267", #ホンダ(本田技研工業)
            "jp.stock.8306", #三菱UFJフィナンシャル・グループ
            "jp.stock.4503", #アステラス製薬
            "jp.stock.4063", #信越化学工業
            "jp.stock.7974", #任天堂
            "jp.stock.6981", #村田製作所
            "jp.stock.3382", #セブン&アイ・ホールディングス
            "jp.stock.9020", #東日本旅客鉄道
            "jp.stock.8802", #三菱地所
            "jp.stock.9022", #東海旅客鉄道
            "jp.stock.9984", #ソフトバンクグループ
            "jp.stock.6861", #キーエンス
            "jp.stock.6501", #日立製作所
            "jp.stock.6752", #パナソニック
            "jp.stock.6758", #ソニー
            "jp.stock.6954", #ファナック
            "jp.stock.7203", #トヨタ自動車
            "jp.stock.7751", #キヤノン
            "jp.stock.4452", #花王
            "jp.stock.6098", #リクルートホールディングス     
         ],

使用するデータの設定

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

作成したシグナルの登録

ctx.regist_signal("my_signal", _my_signal)

シグナルを作成する関数_my_signal(後述)を"my_signal"という名前で登録します。決まり文句です。


_my_signal - 売買シグナルの定義

_my_signal関数でMACDによる売買シグナルを定義します。

def _my_signal(data):
    #終値のデータを取得
    cp=data["close_price_adj"].fillna(method="ffill")

    syms = data.minor_axis   # 銘柄リストの作成
    dates = data.major_axis  # 日付リストの作成

    #データを格納する場所
    macd = pd.DataFrame(data=0.0, columns=syms, index=dates)
    macdsignal = pd.DataFrame(data=0.0, columns=syms, index=dates)
    macdhist = pd.DataFrame(data=0.0, columns=syms, index=dates)

    #TA-LibによるMACDの計算
    for (sym,val) in cp.items():
      macd[sym],macdsignal[sym],macdhist[sym] = ta.MACD(cp[sym],fastperiod=12,slowperiod=26,signalperiod=9)

    #売買シグナル生成部分
    buy_sig = (macd > macdsignal) & (macd.shift(1) < macdsignal.shift(1))
    sell_sig = (macd < macdsignal) & (macd.shift(1) > macdsignal.shift(1))

    #market_sigという全て0が格納されているデータフレームを作成
    market_sig = pd.DataFrame(data=0.0, columns=syms, index=dates)

    #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 {
      "MACD": macd, 
      "MACDSignal": macdsignal, 
      "MACDHist": macdhist, 
      "market:sig": market_sig,
    }

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

各変数ごとに分けて説明していきます。

終値のデータを取得

    #終値のデータを取得
    cp=data["close_price_adj"].fillna(method="ffill")

MACDの計算に終値を採用します。

data内に‘close_price_adj’として入っています。また、.fillnaで欠損値を補完します。method‘ffill’と指定することで、欠損する前の値で、その欠損値を埋めることができます。

銘柄・日付のリストを作成

    syms = data.minor_axis   # 銘柄リストの作成
    dates = data.major_axis  # 日付リストの作成

取引対象の銘柄と、取引期間の日付のリストを作成しています。
指標の値を計算する際などに使用します。

MACDのデータフレームを作成

    # MACDの計算結果を格納する場所
    macd = pd.DataFrame(data=0.0, columns=syms, index=dates)
    macdsignal = pd.DataFrame(data=0.0, columns=syms, index=dates)
    macdhist = pd.DataFrame(data=0.0, columns=syms, index=dates)

計算したMACDの値を格納するために空のデータフレームを作成しています。
columns(横軸)に銘柄、index(縦軸に日付)で中身の値は全て0が入っています。

    #TA-LibによるMACDの計算
    for (sym,val) in cp.items():
      macd[sym],macdsignal[sym],macdhist[sym] = ta.MACD(cp[sym],fastperiod=12,slowperiod=26,signalperiod=9)

銘柄リストの銘柄をひとつずつ取り出し、MACDを計算し、計算結果を先程の3つの空のデータフレームに格納します。
価格データ(終値)とMACDを計算する期間であるfastperiod、slowperiod、signalperiodを指定するだけで計算結果が出ます。
今回は、fastperiod(12日)、slowperiod(26日)、signalperiod(9日)と一般的なものを採用しています。

売買シグナルの作成

    # 売買シグナル生成部分
    buy_sig = (macd > macdsignal) & (macd.shift(1) < macdsignal.shift(1))
    sell_sig = (macd < macdsignal) & (macd.shift(1) > macdsignal.shift(1))

計算したMACDの値を利用して、売買シグナル生成の基準を決めています。
今回はmacdとmacdsignalのゴールデンクロス、デッドクロスで売買シグナルを生成します。

marketシグナルの作成

    # market_sigという全て0が格納されているデータフレームを作成
    market_sig = pd.DataFrame(data=0.0, columns=syms, index=dates)

    # 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

このままだと、buy_sigとsell_sigが二つ同時に起こる可能性があるので、その対策をしていきます。
ここでは、market_sigという市況シグナルを定義し、買いシグナルは1.0、売りシグナルは-1.0、取引しない状態を0で出すようにしていきます。
また、buy_sigとsell_sigが二つ同時に起こった場合、取引しないようにしていきます。

戻り値の作成

    return {
      "MACD": macd, 
      "MACDSignal": macdsignal, 
      "MACDHist": macdhist, 
      "market:sig": market_sig,
    }

後ほど利用するデータフレームを定義して残します。 また、チャートで表示する際の項目名も定義します。
例えば「buy_sig」というデータフレームを""buy:sig""という名前でチャートの下に表示させます。
取引に使用するmarket_sigも設定します。

handle_signals - 日ごとの処理部分の記述

※QuantX Factory tutorialの記事で共通している部分です。すでに理解している方は読み飛ばしていただいて結構です。


handle_signals

売買を行うための設定

market_sig = current["market:sig"]

initialize_my_signal内で作成したシグナルをhandle_signalsでも使用できるように、market_sigに格納します。

done_syms = set([])
none_syms = set([])

done_symsは利益確定や損切が行われた銘柄を格納するための集合型
none_symsは保有している銘柄に存在しない銘柄を格納するための集合型
です。

# portfolio.positions(保有している銘柄)に対象銘柄(sym)が存在するかのチェック
  for (sym, val) in market_sig.items():
    if sym not in ctx.portfolio.positions:
      none_syms.add(sym)

保有している銘柄に対象の銘柄が存在するかをチェックしています。
存在しない場合はnone_symsに格納します。
(保有していない銘柄に売り注文が入ることを防ぐためです。)

  # portfolio.positions(保有している銘柄)のそれぞれの銘柄(sym)の保有株数が0ではないかのチェック
  for (sym, val) in ctx.portfolio.positions.items():
    if val["amount"] == 0:
      none_syms.add(sym)

保有株数がゼロでないかをチェックしています。
保有数がゼロの銘柄はnone_symsに格納します。
(保有数が0の銘柄に売り注文が入ることを防ぐためです。)

利益確定・損切の設定

for (sym, val) in ctx.portfolio.positions.items():
    # 損益率の取得
    returns = val["returns"]
    if returns < -0.03:  # 損益率が-3%未満(絶対値で3%より大きい損)の場合
      # 損切りのための売り注文
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="損切り(%f)" % returns)
      # 利益確定及び損切りが行われた銘柄を格納するset型にsymに代入されている銘柄を追加
      done_syms.add(sym)
    elif returns > 0.05:  # 損益率が+5%より大きい場合
      # 利益確定(利確)のための売り注文
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
      # 利益確定及び損切りが行われた銘柄を格納するset型にsymに代入されている銘柄を追加
      done_syms.add(sym)

損益率が-3%を下回ったら損切り、5%を上回ったら利益確定を行います。
ctx.portfolio.positionsは各銘柄のデータが格納されています。

損切もしくは利益確定を行った銘柄は、done_symsに格納します。

データ型などの詳細はQuantX Factoryのドキュメント をご覧下さい。

シグナルに従って売買する部分

買い注文を行う部分
buy = market_sig[market_sig > 0.0]  # 買いシグナル
  for (sym, val) in buy.items():  # 買いシグナルが出ている銘柄を1つずつ処理
    # done_symsまたはnone_symsにsymがある場合
    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))

market_sigが0より大きいものを買いシグナルとしてbuyに格納しています。
order関数にsec.unit() * 1を与え、一単元分の買い注文をしています。

売り注文
  sell = market_sig[market_sig < 0.0]  # 売りシグナル
  for (sym, val) in sell.items():  # 売りシグナルが出ている銘柄を1つずつ処理
    # done_symsまたはnone_symsにsymがある場合
    if (sym in done_syms) | (sym in none_syms):
      continue  # 処理をスキップ
    # 売り注文
    sec = ctx.getSecurity(sym)
    sec.order(sec.unit() * -1,orderType=ot, comment="SIGNAL SELL")

売り注文の場合も買いの場合とほとんど同じですが、注文をする際のorder関数の引数に与える単元数はマイナスであることに注意して下さい。
このコードで一単元分の売り注文をしています。


バックテスト

スクリーンショット 2019-12-25 14.30.37.png

関連リンク

参考にさせていただいたものです。
https://www.jibunbank.co.jp/products/foreign_deposit/chart/help/macd/

勉強会の宣伝

詳細はこちらだよ
Pythonアルゴリズム勉強会HP:https://python-algo.connpass.com/
(connpassって言うイベントサイトに飛びます)
勉強会やってます!
場所:神田 千代田共同ビル4階 SmartTrade社オフィス
備考:お菓子と終わりにお酒を飲みながら参加者と歓談できます!

免責注意事項

このコードや知識を使った実際の取引で生じた損益に関しては一切の責任を負いかねますので御了承下さい.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
4
Help us understand the problem. What are the problem?