チャネルブレイクアウト戦略botの解説
チャネルブレイクアウト戦略とは
久しくトレンドらしいトレンドが出ず、かつて流行した非元祖ドテン君のようなトレンドフォロー型のbotには厳しい値動きがビットコインでは続いています。しかしながら狭レンジという一種のトレンドも、いつかは終わるのではないでしょうか。上向きか下向きかはともかくとして。
そろそろ次の一手を仕込んでおきませんか。
かつてタートルズと呼ばれた投資集団があり、彼らはドンチアン・チャネル・ブレイクアウト戦略で成功を収めました。詳細は以下の書籍で詳しく語られています。
チャネルブレイクアウト戦略とは一般に、一定期間の高値(安値)を現値が抜いたら買い(売り)参入し、別のあるいは同一の期間の安値(高値)を現値が抜いたら退出をするというものです。
つまり方向感がない相場では高値を買わされ安く売らされを続けることになり、資金とストレスを律するのが大変です。小さな損に何度も耐えながらいつか来るであろう大きな波を待ちます。そしていざトレンドに乗れても、今度は含み益が消える不安に抗いながらポジションを維持しなければならないのです。
しかし、ひとたびトレンドが継続すると大きく利益を伸ばせることが、この戦略の魅力となっています。
- - -
このスクリプトでできること
ここに掲載したPythonスクリプトはタートル流トレーディング規則を参考に、チャネルブレイクアウト部分のみをルール化してBitMEXのXBTUSD Perpetualマーケットにおいて自動売買をするよう作られています。
「損がなかなか切れない」「益をすぐ確定したくなる」のが人間心理です。しかしbotにならば人間の感情と真逆であるところの、規律ある投資行動を任せてしまうことができます。
本来のタートル流規則ではATR(アベレージ・トゥルー・レンジ; ある期間の指数平均値幅)によるサイズ設定やストップロスルールが決められていますが、このスクリプトでは単純なチャネルブレイクアウトのみを再現しています。
ここから先は、このbotの機能を紹介していきます。該当する部分のコードを抜粋して掲載しますので、無料部分だけでもbot製作の参考にしていただければ幸いです。
有料エリアには動作するコード全体を掲載しています。無料エリアとはバージョンが異なることがあります。ご了承ください。
- - -
# 戦略に採用する足 ccxt依存なので'1m', '5m', '1h', '1d'のいずれか
RESOLUTION = '1d'
SECONDS = 86400
# 未確定足を除く何本でチャネルを判定するか 取得上限499本
# 期間1st: entry条件 >= 期間2nd: exit条件
FIRST_PERIOD_STICKS = 55
SECOND_PERIOD_STICKS = 20
"""中略"""
def fetch_candles():
"""candlesを取得して最大値最小値を取り出す"""
for i in range(RETRY):
try:
now = time() * 1000
since = FIRST_PERIOD_STICKS
since = (
now
- (since if RESOLUTION != '1d' else
since if since > 40 else
40)
* SECONDS
* 1000
)
candles = bitmex.fetchOHLCV(
'BTC/USD',
timeframe=RESOLUTION,
since=since,
limit=500,
)
except Exception as e:
logger.error('fetch_candles_error: {}'.format(e))
sleep(ERROR_SLEEP)
else:
candles = np.array(candles)
entry_line = candles[
-FIRST_PERIOD_STICKS-1:-1,
OHLC_INDEX
]
exit_line = candles[
-SECOND_PERIOD_STICKS-1:-1,
OHLC_INDEX
]
hL_channel = [
np.amax(entry_line),
np.amin(entry_line),
np.amax(exit_line),
np.amin(exit_line),
]
return hL_channel
未確定足を除いた55本と20本の最高値最安値をそれぞれ取り出します。この4つの数値を元にストップ注文を出すというのがこのbotの動作の根幹となります。設定は容易に変更することができます。
# 有名なあのbot
RESOLUTION = '1h'
SECONDS = 3600
FIRST_PERIOD_STICKS = 18
SECOND_PERIOD_STICKS = 18
# 後述
OC_MODE = False
例えば1時間足にして期間1と期間2の両方を18本で取るだけで、あの著名なドテンbotに早変わりします。
# 発注数量USD 0なら自動計算(fixed or calculated)
LOT = 0
# 証拠金残高に対するレバレッジ倍率 LOTが0の時に有効
LEVERAGE = 1.0
"""中略"""
def fetch_position():
"""現値と建玉を取得しLOTをセットする"""
for i in range(RETRY):
try:
inst_dict = bitmex.publicGetInstrument({
'symbol': 'XBTUSD',
'columns': json.dumps(['lastPrice']),
})[0]
pos_dict = bitmex.privateGetPosition({
'symbol': 'XBTUSD',
'columns': json.dumps(
['avgEntryPrice', 'currentQty']),
})[0]
except Exception as e:
logger.error('fetch_position_error: {}'.format(e))
sleep(ERROR_SLEEP)
else:
last_price = inst_dict['lastPrice']
entry_price = pos_dict['avgEntryPrice']
current_qty = pos_dict['currentQty']
break
for i in range(RETRY):
try:
bal_dict = bitmex.privateGetUserMargin({
'columns': json.dumps(['marginBalance'])
})
except Exception as e:
logger.error('fetch_balance_error: {}'.format(e))
sleep(ERROR_SLEEP)
else:
total_BTC = bal_dict['marginBalance'] * 0.00000001
total_USD = total_BTC * last_price
order_lot = LOT if LOT else int(total_USD * LEVERAGE)
break
position = [
last_price,
entry_price,
current_qty,
total_BTC,
total_USD,
order_lot,
]
return position
発注数量を口座残高の何倍にするか設定すると、含み損益も含めた数値をもとにロットが計算されます。倍率は1倍未満でも構いません。もちろん固定ロットにもできます。発注量の多すぎ少なすぎにはお気をつけください。
- - -
def post_orders(
position_sign,
order_side,
last_price,
current_qty,
order_lot,
break_price1,
break_price2,
**kwargs):
"""条件に応じた注文を出す"""
# ポジションがあればexit_stopを入れる
if position_sign != 'NONE':
for i in range(RETRY):
# closeを出すとともに次のbreakを出しておく
order_params = [{
'symbol': 'XBTUSD',
'ordType': 'Stop',
'side': order_side,
'orderQty': None,
'stopPx': break_price2,
'execInst': 'LastPrice, Close',
}, {
'symbol': 'XBTUSD',
'ordType': 'Stop',
'side': order_side,
'orderQty': order_lot,
'stopPx': break_price1,
'execInst': 'LastPrice',
}]
try:
bitmex.privatePostOrderBulk({
'orders': json.dumps(order_params),
})
except Exception as e:
logger.error('exit_orders_error: {}'.format(e))
sleep(ERROR_SLEEP)
else:
return True
# ポジションがなければチャネルの外側にentry_stopを入れる
else:
for i in range(RETRY):
order_params = [{
'symbol': 'XBTUSD',
'ordType': 'Stop',
'side': 'Buy',
'orderQty': order_lot,
'stopPx': break_price1,
'execInst': 'LastPrice',
}, {
'symbol': 'XBTUSD',
'ordType': 'Stop',
'side': 'Sell',
'orderQty': order_lot,
'stopPx': break_price2,
'execInst': 'LastPrice',
}]
try:
bitmex.privatePostOrderBulk({
'orders': json.dumps(order_params),
})
except Exception as e:
logger.error('entry_orders_error: {}'.format(e))
sleep(ERROR_SLEEP)
else:
return True
return False
注文部分の一部抜粋です。チャネルブレイクアウト戦略では高値と安値や参入価格と退出価格など、複数の注文を同時に出すことになります。このコードではバルク注文としてまとめて送信しています。
def amend_orders(
order_id_HN,
order_id_LF,
break_price_HN,
break_price_LF,
order_lot_HN,
order_lot_LF,
**kwargs):
"""チャネル変化にそって注文を修正する"""
for i in range(RETRY):
order_params = [{
'symbol': 'XBTUSD',
'orderID': order_id_HN,
'leavesQty': order_lot_HN,
'stopPx': break_price_HN,
}, {
'symbol': 'XBTUSD',
'orderID': order_id_LF,
'leavesQty': order_lot_LF,
'stopPx': break_price_LF,
}]
try:
bitmex.privatePutOrderBulk({
'orders': json.dumps(order_params),
})
except Exception as e:
logger.error('amend_orders_error: {}'.format(e))
sleep(ERROR_SLEEP)
else:
return True
return False
高値安値が変化した場合は、注文を出し直すのではなく注文修正でストップ価格をずらしています。それと同時に次のブレイク時のロットサイズも調整します。
- - -
このbotの特徴的な機能
レンジ相場であってもビットコインの値動きは大きく、時にローソク足の上下に長いヒゲを作ることがあります。そのため通常のチャネルブレイクアウト戦略のように最高値と最安値でチャネル判定をすると、レンジの実勢に比べて参入退出価格が大きく離れてしまうことがあります。
# OpenClose_MODE チャネルを実体(除ヒゲ)で判定する
OC_MODE = False
OHLC_INDEX = [1, 4] if OC_MODE else [2, 3]
そこでこのbotでは、ローソク足の実体である始値と終値だけを結んでチャネル判定ができるOC_MODEを備えています。Over_ClockedではなくOpen_Closeです。通常のHigh_Lowよりも狭い値幅でチャネル判定をするので参入退出の機会が増える一方で、だましにも掛かりやすくなることには注意がいります。掲載コードの初期値ではこの機能はオフです。
暗号通貨の取引所ではチャネルブレイクするような価格変動があった時に、混雑からか注文が通らなかったりポジションが取得できないことがままあります。そこでこのスクリプトでは注文はあらかじめ逆指値で出しておくように統一しています。
# 建玉数が規定LOTを大きく(e.g. 1.5倍)超えていたら
# 現値にstopを入れて超過分を削る(maintain the qty limit)
# (API混雑時などの意図しない注文重複を想定)
if abs(current_qty) > order_lot * 1.5:
decrease_lot = abs(current_qty) - order_lot
order_params = [{
'symbol': 'XBTUSD',
'ordType': 'Stop',
'side': order_side,
'orderQty': decrease_lot,
'stopPx': last_price,
'execInst': 'LastPrice, ReduceOnly',
}]
ポジション取得ができず二重注文となった場合などに建玉を持ちすぎないように、建玉が規定ロットを超えていたら規定数まで減らすようにコーディングしています。
- - -
"""設定ここから"""
"""edit settings to add your Keys and change parameters"""
APIKEY = 'APIKeyAPIKeyAPIKeyAPIKeyAPIKeyAPIKey'
SECRET = 'SecretSecretSecretSecretSecretSecretSecretSecret'
TESTNET_APIKEY = 'APIKeyAPIKeyAPIKeyAPIKeyAPIKeyAPIKey'
TESTNET_SECRET = 'SecretSecretSecretSecretSecretSecretSecretSecret'
TESTNET = False
DISCORD_URL = ''
# DISCORD_URL = (
# 'https://discordapp.com/api/webhooks/'
# 'IdIdIdIdId/'
# 'TokenTokenTokenTokenTokenToken'
# )
# stopをチャネル上下端の何ドル外側に仕掛けるか 0.5USD単位
# how many $ outside of the channel(0 or int multiple of 0.5)
OFFSET = 0.5
# order直後の待機秒数(seconds),
# ロジック全体のループ待ち秒数(seconds)
ORDER_WAIT = 40
LOOP_WAIT = 20
# error時の再試行回数(times),
# error時の休止秒数(seconds)
RETRY = 10
ERROR_SLEEP = 6
# ログファイル名をお好みで
LOGFILE_DIR = './log/'
LOGFILE_PREFIX = 'cRe'
LOGFILE_DATE = strftime('%Y%m%d%H%M')
2019-03-23 04:40:37,623 - INFO - system'cRe5520' ver.2.1.323 cRe201903230440.log
2019-03-23 04:40:37,624 - INFO - RESO: '1h', 1ST: 20, 2ND: 10, OFFSET: 0.5, OC: False
2019-03-23 04:40:37,627 - INFO -
2019-03-23 04:40:37,683 - INFO - hL_channel: [4037.0, 3938.5, 4000.0, 3965.0]
2019-03-23 04:40:37,705 - INFO - last_price: 3983.5, entry_price None, current_qty: 0
2019-03-23 04:40:37,718 - INFO - balance: 1.06723304
2019-03-23 04:40:37,748 - INFO - 'put_amend_orders': High: 4037.5, Low: 3938.0
2019-03-23 04:41:17,977 - INFO -
2019-03-23 04:41:17,995 - INFO - hL_channel: [4037.0, 3938.5, 4000.0, 3965.0]
2019-03-23 04:41:18,016 - INFO - last_price: 3978.5, entry_price None, current_qty: 0
2019-03-23 04:41:38,062 - INFO -
2019-03-23 04:41:38,150 - INFO - hL_channel: [4037.0, 3938.5, 4000.0, 3965.0]
2019-03-23 04:41:38,170 - INFO - last_price: 3978.5, entry_price None, current_qty: 0
MAINNETとTESTNETとを容易に切り替えられるようにしてあります。また動作ログを残しますので稼働状況が後からも確認できます。注文処理の直後に簡単なレポート通知をDiscordに飛ばすこともできます。
### debug ###
RESTARTER = 0
"""中略"""
### debug ###
restart_counter = RESTARTER if RESTARTER else 0
while True:
### debug ###
if RESTARTER:
logger.debug(
'loop_counter: {}'.format(restart_counter))
restart_counter -= 1
if restart_counter <= 0:
logger.warning('counter_value_has_reached')
logger.warning('restart_script')
os.execv(sys.executable, (
sys.executable,
os.path.abspath(__file__),
))
ログファイルを一定サイズに細分化したり、コード修正を都度自動的に反映させたりと、開発上の便宜のためにスクリプトの自動再起動機能を埋め込みました。開発用のつもりですが、掲載コードにもそのまま残してありますので設定をすればお使いいただけます。変数RESTARTERがスイッチでありカウンターです。
- - -
このbotを動かすには
私はこのbotをAmazon Web ServicesのEC2で動作させています。
有料エリアのコードを動かすにはPython3スクリプトの動作環境を構築できるスキルが必要です。
必須の外部モジュールはccxtとnumpyです。必要に応じてrequests(Discord通知用)とWebSocket公式コネクタを導入してください。WebSocketで現在価格や証拠金残高を取得するコードが実験的に埋めてあります。
sudo /usr/bin/pip-3.6 install --upgrade pip
sudo /usr/local/bin/pip3 install ccxt
sudo /usr/local/bin/pip3 install numpy
sudo /usr/local/bin/pip3 install requests
sudo /usr/local/bin/pip3 install bitmex-ws
上記の数行を見て何をすべきかわかる方なら動作設定はできそうです。逆に自分で解決する自信のない方はこのコードに大切なお金を支払ってはいけません。
冒頭で述べたように、対象となる取引サービスはBitMEXのXBTUSD Perpetualです。BitMEXの口座開設やAPIKEY取得についてもこの記事では解説しません。
PS C:\Users\home> pip install ccxt
PS C:\Users\home> pip install numpy
(optional)
PS C:\Users\home> pip install request
PS C:\Users\home> pip install bitmex-ws
- - -
過去の更新履歴
- - -
おわりに
RESOLUTION = '1h'
FIRST_PERIOD_STICKS = 60
SECOND_PERIOD_STICKS = 18
OC_MODE = True
このコードの当初設定である55日参入の20日退出では、参入の機会があまり発生しません。ですので例えば1時間足の数十時間で参入し十数時間での退出をするなど、足元の値動きを見ながら設定値を探ってはいかがでしょうか。一例としては1時間足60本で参入し18本逆行で退出するくらいを手始めに調整ができそうです。
RESOLUTION = '1h'
FIRST_PERIOD_STICKS = 50
SECOND_PERIOD_STICKS = 10
OC_MODE = False
勝率が高くはない戦略ですから、小さく続く負けで消耗しないように、レバレッジは低めにしておいたほうがよいでしょう。
またBitMEXでは成行手数料が高いので、売買が高頻度になり値幅も小さい5分足以下でチャネルブレイクアウト戦略を試みても、利益を出すのは難しいかもしれません。
しかし時間軸を伸ばしてみるとどうでしょうか。
ProjectBBBさんによる上記の記事には、同戦略の特徴とそれにどう向き合えばよいかが分かりやすくまとまっています。ご一読をお勧めします。
日足や1時間足で戦略を組みトレンド発生をじっくり待つのが、このbotのお勧めの使い方です。私自身もそうして稼働させています。
- - -
おまけ
- - -
解説記事はここまでです。以下の有料エリアに全体のコードを掲載しました。'cRe5520'というbot名称の由来は秘密です。皆さんのところにも大きなトレンドが訪れるよう願っています。
感情に左右されない規律あるトレードを、あなたも体験してみてください。
for the Disciplined Trading.
Channel breakout trading strategy bot for BitMEX
- system'cRe5520' ver.2.8a.0606a
Channel breakout trading strategy bot for FTX
- system'cRe5520' ver.3.0a.0404
Channel breakout trading strategy bot for Bybit
- system'cRe5520' ver.3.3a.0404
Channel breakout trading strategy bot for Binance Futures
- system'cRe5520' ver.3.6a.0404
以下がFTX用とBybit用、そしてBinance Futures用コードへのリンクです。
ご購入いただき、ありがとうございます。
Thank you so much for your purchase.
I hope you will have good fortune!
RESOLUTION = '1d' FIRST_PERIOD_STICKS = 14 SECOND_PERIOD_STICKS = 3 MARKET_ID = 'ETHUSD' OC_MODE = True