ビットコインの「勢い」に乗る作戦!でも、うまくいかなかったのはなぜ?
この作戦は、ビットコインの値段が「勢いよく上がっているか」「勢いよく下がっているか」を見て、買うか売るかのタイミングを決める、というものです。1時間ごとの値段の動きを使って、約4ヶ月間、実際に試してみました。でも、残念ながら結果は損をしてしまいました…。一体なぜでしょうか?一緒に探っていきましょう。
導入と前提条件
この作戦は、ビットコインの値段が「勢いよく上がっているか」「勢いよく下がっているか」を見て、買うか売るかのタイミングを決める、というものです。1時間ごとの値段の動きを使って、約4ヶ月間、実際に試してみました。でも、残念ながら結果は損をしてしまいました…。一体なぜでしょうか?一緒に探っていきましょう。
【検証】戦略のバックテスト概要
- 戦略名: Time Series Momentum を使用したトレンド追従戦略
- 対象銘柄: BTC/USDT
- 時間足: 1h
- 期間: 2025-05-08〜2025-09-05(119日間)
- 初期資金: $10,000
- 手数料・スリッページ: 0.1% / 0.1%
- 取引所: binance
Time Series Momentum の理論的背景
この作戦の元になる考え方は、「一度勢いがついたものは、しばらくその勢いが続くことが多い」というものです。例えば、サッカーの試合で、あるチームがどんどんゴールを決めて勢いに乗ると、その調子のまま勝ち進むことがありますよね。それと同じで、ビットコインの値段も、上がるときはしばらく上がり続け、下がるときはしばらく下がり続けることがある、という考え方に基づいています。この「勢い」を数字で表して、買うか売るかの合図にするのが、この作戦なんです。
具体的な売買ルール(今回の検証)
エントリー条件
- 12時間前の値段よりも今の値段が上がっていて、「上がる勢いがついた!」と判断したら、買うタイミングです。
- 12時間前の値段よりも今の値段が下がっていて、「下がる勢いがついた!」と判断したら、売るタイミングです。
エグジット条件
- 一度買ったら、上がる勢いがなくなったり、反対に下がる勢いが強くなったら、売って取引を終わりにします。
- 一度売ったら、下がる勢いがなくなったり、反対に上がる勢いが強くなったら、買い戻して取引を終わりにします。
リスク管理
取引をするとき、もし予想が外れてしまっても、大きな損にならないようにすることがとても大切です。例えば、買った値段から少し下がったらすぐに売る、というようなルールを決めておくと、損を小さくできます。
再現手順(HowTo)
- Python/依存(ccxt, pandas, ta)をインストール
- ccxtでBTC/USDTのOHLCVを取得して前処理
- 『Time Series Momentum』に必要な指標を算出(ta 等)
- 閾値・クロス条件から売買シグナルを生成
- 手数料・スリッページを加味して検証・評価
【結果】パフォーマンス
価格の推移
資産の推移
パフォーマンス指標
指標 | 値 |
---|---|
総トレード数 | 205回 |
勝率 | 16.1% |
平均利益 | 0.97% |
平均損失 | -0.63% |
期待値 | -0.37% |
プロフィットファクター | 0.29 |
最大ドローダウン | 54.25% |
最終リターン | -53.82% |
シャープレシオ | -1.61 |
HODL(Buy&Hold) | 9.89% |
HODL戦略との比較
実装コード(Python)
"""
Time Series Momentum Trading Signal
時系列モメンタム戦略
"""
import pandas as pd
import numpy as np
def calculate_time_series_momentum_signals(df: pd.DataFrame,
lookback: int = 12) -> pd.DataFrame:
"""
Time Series Momentum戦略のシグナル生成
Parameters:
-----------
df : pd.DataFrame
OHLCVデータ
lookback : int
ルックバック期間(デフォルト: 12)
Returns:
--------
pd.DataFrame
シグナルが追加されたDataFrame
"""
df = df.copy()
# 時系列モメンタム
df['tsm'] = (df['close'] - df['close'].shift(lookback)) / df['close'].shift(lookback)
# シグナル初期化
df['signal'] = 0
df['is_buy'] = False
df['is_sell'] = False
position = 0
for i in range(lookback, len(df)):
# 買いシグナル(正のモメンタム)
if position <= 0 and df['tsm'].iloc[i] > 0:
df.loc[df.index[i], 'is_buy'] = True
df.loc[df.index[i], 'signal'] = 1
position = 1
# 売りシグナル(負のモメンタム)
elif position >= 0 and df['tsm'].iloc[i] < 0:
df.loc[df.index[i], 'is_sell'] = True
df.loc[df.index[i], 'signal'] = -1
position = -1
else:
df.loc[df.index[i], 'signal'] = position
df['signal'] = df['signal'].fillna(0)
return df
なぜこの結果になったのか(3つの理由)
- 1この作戦は、勢いが「続けば」もうかります。でも、ビットコインは値段が急に大きく変わることがあるので、勢いがすぐに変わってしまい、うまくもうけられなかったのかもしれません。
- 2「12時間前と比べる」というルールが、今のビットコインの動きには合っていなかった可能性があります。もっと短い時間や、もっと長い時間で比べた方が良かったかもしれません。
- 3勝率が16.1%とすごく低かったのが大きな理由です。205回も取引したのに、ほとんどの取引で勝てなかったので、最終的に損をしてしまいました。
この結果から学べる3つの教訓
- 1「昔の勢いがこの先も続くとは限らない」ということを学びました。特にビットコインのように値段の動きが激しいものだと、その通りになりやすいのかもしれません。
- 2作戦がうまくいくかは、何で試すか(今回はビットコイン)や、どれくらい昔のデータを見るか、ということで結果が全然変わってくることを学びました。
- 3勝率が低くても、一回の勝ちでたくさんもうければ、全体でプラスになることもあります。でもこの作戦では、勝率も低く、一回のもうけも大きくなかったので、結果的に損をしてしまいました。
リスク管理の具体的手法
取引量の決め方
一回の取引で使うお金の量を、自分が持っているお金の、ほんの少しの量(例えば1%や2%)にします。こうすることで、もし負けても、全体のお金があまり減らないようにできます。
損失が大きくなったときの対処法
もし、持っているお金が、決めておいた割合(例えば10%)以上減ってしまったら、一度すべての取引をやめて、落ち着いて作戦を見直します。
資金管理の方法
全体でいくらまでのお金を使うか決め、その中で取引します。また、一回の取引で、最悪これだけは損しても大丈夫、という金額の限界を決めておくことも大切です。
改良案の具体的提案
- 「勢い」がなくなったときや、反対の勢いが強くなったときに、もっと早く取引を終わりにするように、ルールを厳しくしてみる。
- 過去をふりかえる時間を「12時間」だけでなく、色々な時間で試してみて、ビットコインに一番合う時間を見つける。
- 「勢い」がなくなったときに、すぐに反対の取引をするのではなく、一度立ち止まって様子を見るルールを加えて、意味のない取引を減らす。
実用性の向上(運用上の注意)
- この作戦をそのまま使うのではなく、まずは少ないお金で試してみたり、昔のデータでうまくいくか確かめてから使ってみましょう。
- ビットコインの値段が大きく動きそうなニュースがあるときや、世の中が不安定なときは、この作戦がうまくいかないかもしれないので、注意が必要です。
- その時々の様子に合わせて、過去をふりかえる時間(パラメータ)を変えてみるのも良いかもしれません。
検証の透明性と信頼性
- データの出所: この結果は、過去のビットコイン(BTC/USDT)の1時間ごとの値段のデータ(その時間のはじめの値段、一番高かった値段、一番安かった値段、終わりの値段)を使って計算しました。
- 検証のやり方: 昔のデータを使って、「もしこの作戦を実際にやっていたら、どれくらいもうかったり損したりしたかな?」というお試し計算(シミュレーション)をして、その結果を調べました。
- コード: この計算をするためのプログラムは、ちゃんと用意されていますので、誰でも同じように確かめることができます。
- 注意事項: このお話は、あくまで昔のデータで計算した結果です。この先も同じようにもうかることを約束するものではありません。お金を使うときは、自分でよく考えて決めましょう。