自動売買ロジックは非常に多く存在します。テクニカル指標の数だけプログラム化することが可能です。今回は酒田五法の赤三兵と黒三兵(三羽鳥)を、自動売買ロジックとして実装してみましょう。
Contents
酒田五法の赤三兵と黒三兵(三羽鳥)とは
引用:BTCFXで酒田五法の赤三兵・黒三兵の自動売買ロジックを作る
酒田五法とは、「酒田罫線(さかたけいせん)」とも呼ばれ、江戸時代の天才的な相場師であった本間宗久が考案したといわれています。江戸時代から信頼されている代表的(一般的)なテクニカル分析です。
酒田五法の5つの法則の一つで、陽線または陰線が3本並んで、同じ方向に階段状になって出現するものであり、代表的なものとして「赤三兵」と「黒三兵」があり、その他にも、「赤三兵先詰り」や「赤三兵思案星」、「仕掛け花火」、「坊主三羽」、「同事三羽」、「小石崩れ」などがあります。
引用:https://www.ifinance.ne.jp/learn/technical/twd135.html
ロジックの定義
ロジックの定義をします。
赤三兵
赤三兵陽線が3本、連続で同じ方向(上昇)にある状態を指し、相場が上昇局面入りするサインとされています。日足より週足で現れた方が、より強い上昇に向かうというイメージです。
1.3足連続で(終値>始値)の足が続いている
2.3回連続で始値と終値が前の足より上昇している
黒三兵
「三羽烏」とも呼ばれ、陰線が3本、連続で同じ方向(下落)にある状態を指し、相場が下降局面入りするサインとされています。
1.3足連続で(終値<始値)の足が続いている
2.3回連続で始値と終値が前の足より下落している
ルール1、2の両方が必要になります。
「3足連続で 終値>始値 」「3足連続で 終値<始値」で傾向は総合的にみて上昇傾向、下降傾向なのかは判断できますが、陽線が連続で続いていても、その始値や終値が前の足より低い、ということは十分あり得るからです。そのようなローソク足の形では「赤三兵」「黒三兵」とはいえないのです。
追加ルール
上記ルールでは、以下のようなローソク足パターンも検出してしまいます。
引用:BTCFXで酒田五法の赤三兵・黒三兵の自動売買ロジックを作る
上方傾向を確認できますが、傾向度としては弱そうです。ですので、以下のロジックを追加することで信用度が上がると考えられます。
- ローソク足の実態がある程度の大きさである
- ヒゲの割合よりも実体の割合の方が大きい
具体的な値の設定としては以下の通りです。
- 実体の大きさ(上昇率)が始値の0.05%以上
- ヒゲを含む値幅のうち実体の割合が50%以上
1つ目の条件は、「終値/始値 ― 1」の計算結果のことです。取得する時間軸(1分足、5分足、1時間足、1日足など)で変わります。サンプルでは1分足でみるので、「0.05%」にしていきます。2つ目の条件は、「(始値 ― 終値)の絶対値 / (高値 ― 安値)」です。1つ目、2つ目とも最適値というのは試してみないとわかりません。
注意
「ローソク足パターンの傾向分析」の説明や「買いシグナル「赤三兵」は有効か!?」の検証から酒田五法の赤三兵と黒三兵(三羽鳥)単体でのロジックで儲かるとはいえないようです。
本記事では「botにアルゴリズムを組み込み自動売買プログラムを動かす」を観点としているので、複雑な組み合わせのアルゴリズムは考慮していないです。
「赤三兵」のPythonコード
「赤三兵」のPythonコード紹介です。ロジックは以下の通りです。
- 3足連続で(終値>始値)の足が続いている
- 3回連続で始値と終値が前の足より上昇している
の時に、買いシグナルを出すコードとなります。
import requests from datetime import datetime import time def get_price(min): response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc",params = { "periods" : min }) data = response.json() last_data = data["result"][str(min)][-2] return { "close_time" : last_data[0], "open_price" : last_data[1], "high_price" : last_data[2], "low_price" : last_data[3], "close_price":last_data[4] } def print_price( data ): print( "時間: " + datetime.fromtimestamp(data["close_time"]).strftime('%Y/%m/%d %H:%M') + " 始値: " + str(data["open_price"]) + " 終値: " + str(data["close_price"]) ) def check_candle( data ): realbody_rate = abs(data["close_price"] - data["open_price"]) / (data["high_price"]-data["low_price"]) increase_rate = data["close_price"] / data["open_price"] - 1 if data["close_price"] < data["open_price"] : return False elif increase_rate < 0.0005 : return False elif realbody_rate < 0.5 : return False else : return True def check_ascend( data,last_data ): if data["open_price"] > last_data["open_price"] and data["close_price"] > last_data["close_price"]: return True else: return False last_data = get_price(60) print_price( last_data ) flag = 0 while True: data = get_price(60) if data["close_time"] != last_data["close_time"]: print_price( data ) if flag == 0 and check_candle( data ): flag = 1 elif flag == 1 and check_candle( data ) and check_ascend( data,last_data ): print("2本連続で陽線") flag = 2 elif flag == 2 and check_candle( data ) and check_ascend( data,last_data ): print("3本連続で陽線 なので 買い!") flag = 3 else: flag = 0 last_data["close_time"] = data["close_time"] last_data["open_price"] = data["open_price"] last_data["close_price"] = data["close_price"] time.sleep(10)
実行結果サンプルです。
pythonコードの解読(酒田五法の赤三兵・黒三兵)
上記コードを一緒に解読していきましょう。
パート1:ライブラリのインポート
import requests from datetime import datetime import time
処理に必要なライブラリのインポートです。
pythonで外部のURLにアクセス(CryptowatchのAPIを使う)するために「requests」ライブラリをインポートしています。APIで取得したタイムスタンプ(UNIX時間)は我々がパッとみた時に把握しにくい形式でしたので、人間でもわかりやすい形式に変換するためにdatetimeをインポートしています。「time」はsleep()の処理で使っています。
パート2:ローソク足の価格データを取得する関数
def get_price(min): response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc",params = { "periods" : min }) data = response.json() last_data = data["result"][str(min)][-2] return { "close_time" : last_data[0], "open_price" : last_data[1], "high_price" : last_data[2], "low_price" : last_data[3], "close_price":last_data[4] }
CryptowatchのAPIでBitflyerFXの最新のローソク足の価格データを取得する関数です。
価格データを取得し、配列(辞書リスト)で返すための自作の関数(def get_price())です。
minに外部から60と値を渡すことで1分足のローソク足の価格をデータを取得できます。配列からの取得方法は「bot開発3.CryptowatchのAPIで取得したJSONデータから欲しい数字を取り出す」で基礎的なコードを紹介しています。
パート3:APIで取得したデータを表示させる関数
def print_price( data ): print( "時間: " + datetime.fromtimestamp(data["close_time"]).strftime('%Y/%m/%d %H:%M') + " 始値: " + str(data["open_price"]) + " 終値: " + str(data["close_price"]) )
APIで取得したデータを表示させる関数です。「日時」「始値」「終値」の3つを表示させる関数です。
パート4:取得した各ローソク足(単体)が条件を満たしているかどうかを確認する関数
def check_candle( data ): realbody_rate = abs(data["close_price"] - data["open_price"]) / (data["high_price"]-data["low_price"]) increase_rate = data["close_price"] / data["open_price"] - 1 if data["close_price"] < data["open_price"] : return False elif increase_rate < 0.0005 : return False elif realbody_rate < 0.5 : return False else : return True
取得した各ローソク足(単体)が条件を満たしているかどうかをチェックするために、check_candle()です。
「realbody_rate」「increase_rate」の変数に計算結果を代入し、その結果をロジックの定義の追加ルールの条件でどうなっているのかを返しています。
ロジックの定義の追加ルールは以下の2点です。
- 実体の大きさ(上昇率)が始値の0.05%以上
- ヒゲを含む値幅のうち実体の割合が50%以上
条件を1つでも満たしていなければFalseを返し、すべてを満たしていればTrueを返します。
パート5:2本目、3本目のローソク足が上昇しているかどうかを確認する関数
def check_ascend( data,last_data ): if data["open_price"] > last_data["open_price"] and data["close_price"] > last_data["close_price"]: return True else: return False
2本目、3本目のローソク足が上昇しているかどうかを判定するための関数check_ascend() です。
これはロジック定義の記事のルール2
- 赤三兵:3回連続で始値と終値が前の足より上昇している
の部分になります。
大なり小なりで終値・始値を比較し、今回の始値と前回の始値、今回の終値と前回の終値を比較し、両方とも上昇していればTrueを返します。
パート6
last_data = get_price(60) print_price( last_data ) flag = 0
プログラムは、半永久的に動いていることが、botです。プログラムが無限に動いているという必要があるので、その準備となります。
今回は、「前回の終値」と「今回の終値」を比較する必要があるため、比較対象となる値(終値)を取得し、last_dataに代入しています。
flagは「何本連続で陽線が続いているか?」を判定するために使います。初期値として0を入れておき、後続処理で変化するようになっています。
パート7
この部分はWhile文の中身を確認していきましょう。
while True: data = get_price(60) if data["close_time"] != last_data["close_time"]: print_price( data ) if flag == 0 and check_candle( data ): flag = 1 elif flag == 1 and check_candle( data ) and check_ascend( data,last_data ): print("2本連続で陽線") flag = 2 elif flag == 2 and check_candle( data ) and check_ascend( data,last_data ): print("3本連続で陽線 なので 買い!") flag = 3 else: flag = 0 last_data["close_time"] = data["close_time"] last_data["open_price"] = data["open_price"] last_data["close_price"] = data["close_price"] time.sleep(10)
少し長いので小分けにしてみていきましょう。
if文の詳細です、
if data["close_time"] != last_data["close_time"]: print_price( data ) if flag == 0 and check_candle( data ): flag = 1 elif flag == 1 and check_candle( data ) and check_ascend( data,last_data ): print("2本連続で陽線") flag = 2 elif flag == 2 and check_candle( data ) and check_ascend( data,last_data ): print("3本連続で陽線 なので 買い!") flag = 3 else: flag = 0
data[“close_time”]がlast_data[“close_time”]が異なったら、つまり、更新があった場合、変数flagを確認します。
flagが0の場合(まだ1本も陽線のシグナルが出ていない場合)、check_candle()関数を確認します。ifの条件分岐は4つです、
flagが「1」の場合(前回の足が陽線の場合)
check_candle()とcheck_ascend()の両方でチェックし、両方とも満たしていれば、flag = 2をふります。
そして、「2本連続で陽線」を表示させます。
flagが「2」の場合(前の足が2本連続で陽線の場合)
継続的にcheck_candle()とcheck_ascend()の両方でチェックし、、両方とも満たしていれば、flag = 3をふります。
そして、「3本連続で陽線 なので 買い!」を表示させます。
flagがそれ以外の場合、条件に一致しなかった場合、flag = 0となり、ループ処理に戻ります。
条件できちんと段階を踏んでいるところがポイントです。
last_data["close_time"] = data["close_time"] last_data["open_price"] = data["open_price"] last_data["close_price"] = data["close_price"] time.sleep(10)
ローソク足の更新があったので、「前回の価格データ」を「今回の価格データ」で上書きします。次のループからは、「今回の価格データ(の日時)」と次回の価格データの日時を比較して、更新があったかどうかを判断します。
最後に
ロジックの部分の読解でした。
このロジックに売買できる仕組みを組み込めば、売買開始できるということですね。
※注意:本bot開発は「文系でもわかる!BitcoinのBOT自動売買トレードの始め方」をもとに開発・自分なりの解釈用備忘録としています。