仮想通貨トレード テクニカル分析を利用したBOTで勝てるのか
ニューヨーク時間で価格上昇が多いのかを検証
%load_ext autoreload
%autoreload 2
!pip install japanize-matplotlib
import japanize_matplotlib
import requests
import pandas as pd
import matplotlib.pyplot as plt
from pytz import timezone
# ニューヨーク時間を設定
ny_tz = timezone('America/New_York')
# APIリクエストの設定
url = 'https://api.coingecko.com/api/v3/coins/bitcoin/market_chart'
params = {
'vs_currency': 'usd',
'days': '365', # 過去1年
'interval': 'daily'
}
# データの取得
response = requests.get(url, params=params)
data = response.json()
# データの変換
prices = data['prices']
volumes = data['total_volumes']
# DataFrameに変換
df_prices = pd.DataFrame(prices, columns=['timestamp', 'price'])
df_volumes = pd.DataFrame(volumes, columns=['timestamp', 'volume'])
# タイムスタンプを日時に変換
df_prices['date'] = pd.to_datetime(df_prices['timestamp'], unit='ms').dt.tz_localize('UTC').dt.tz_convert(ny_tz)
df_volumes['date'] = pd.to_datetime(df_volumes['timestamp'], unit='ms').dt.tz_localize('UTC').dt.tz_convert(ny_tz)
# 不要な列を削除
df_prices = df_prices.drop(columns=['timestamp'])
df_volumes = df_volumes.drop(columns=['timestamp'])
# データの統合
df = pd.merge(df_prices, df_volumes, on='date')
# 日次リターンの計算
df['return'] = df['price'].pct_change() * 100 # パーセンテージリターン
# グラフの描画
plt.figure(figsize=(14, 7))
# 価格のプロット
plt.subplot(3, 1, 1)
plt.plot(df['date'], df['price'], label='BTC Price (USD)', color='blue')
plt.title('Bitcoin Price (USD)')
plt.xlabel('Date')
plt.ylabel('Price (USD)')
plt.legend()
plt.grid(True)
# 出来高のプロット
plt.subplot(3, 1, 2)
plt.bar(df['date'], df['volume'], label='BTC Volume', color='orange')
plt.title('Bitcoin Trading Volume')
plt.xlabel('Date')
plt.ylabel('Volume')
plt.legend()
plt.grid(True)
# 日次リターンのプロット
plt.subplot(3, 1, 3)
plt.plot(df['date'], df['return'], label='Daily Return (%)', color='green')
plt.title('Bitcoin Daily Return (%)')
plt.xlabel('Date')
plt.ylabel('Return (%)')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
結果 アメリカ時間で価格が上昇した確率 53%
テクニカル分析で有名なMACDで勝てるのか検証
「ビットコインの価格」と「MACD」という指標を使って、過去1年分のデータを分析し、価格の動きをグラフに描くものです。
MACDを利用 エントリーから1日後のリターンを計測
import requests
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from pytz import timezone
# ニューヨーク時間を設定
ny_tz = timezone('America/New_York')
# APIリクエストの設定
url = 'https://api.coingecko.com/api/v3/coins/bitcoin/market_chart'
params = {
'vs_currency': 'usd',
'days': '365', # 過去1年
'interval': 'daily'
}
# データの取得
response = requests.get(url, params=params)
data = response.json()
# データの変換
prices = data['prices']
# DataFrameに変換
df = pd.DataFrame(prices, columns=['timestamp', 'price'])
df['date'] = pd.to_datetime(df['timestamp'], unit='ms').dt.tz_localize('UTC').dt.tz_convert(ny_tz)
df.set_index('date', inplace=True)
df = df.drop(columns=['timestamp'])
# MACD指標の計算
def calculate_macd(df, short_window=12, long_window=26, signal_window=9):
df['ema_short'] = df['price'].ewm(span=short_window, adjust=False).mean()
df['ema_long'] = df['price'].ewm(span=long_window, adjust=False).mean()
df['macd'] = df['ema_short'] - df['ema_long']
df['macd_signal'] = df['macd'].ewm(span=signal_window, adjust=False).mean()
return df
df = calculate_macd(df)
# MACDエントリーシグナルの生成
df['signal'] = np.where(df['macd'] > df['macd_signal'], 1, 0) # MACDがシグナルラインを上回ると1、下回ると0
# 勝敗計算のためのラベルを生成
df['return'] = df['price'].pct_change().shift(-1) * 100 # 翌日のリターン
df['win'] = np.where(df['signal'].shift(1) == 1, np.where(df['return'] > 0, 1, 0), np.nan) # エントリーシグナルと翌日のリターンを比較
df['win'] = df['win'].fillna(0) # NaNを0に置き換え
# 勝率の計算
total_entries = df['signal'].shift(1).sum()
total_wins = df['win'].sum()
winning_rate = (total_wins / total_entries) * 100 if total_entries > 0 else 0
# グラフの描画
plt.figure(figsize=(14, 7))
# 価格の折れ線グラフ
plt.plot(df.index, df['price'], label='BTC Price', color='blue', alpha=0.5)
# エントリーポイントのプロット
buy_signals = df[df['signal'].shift(1) == 1] # MACDがシグナルラインを上回ったポイント
plt.scatter(buy_signals.index, buy_signals['price'], marker='^', color='black', label='Entry Points')
# 勝敗の色分け
colors = np.where(df['win'] == 1, 'green', 'red')
plt.scatter(df.index, df['price'], color=colors, alpha=0.6, label='Win/Loss')
plt.title(f'Bitcoin Price and MACD Entry Points with Win/Loss (Winning Rate: {winning_rate:.2f}%)')
plt.xlabel('Date')
plt.ylabel('Price (USD)')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
結果 勝率 50.64%
MACDを利用したトレードでは勝率は半々なので、ほかの指標との組み合わせを行う必要があります
複数のテクニカルを組合せると勝率が上がるのか検証しましょう
戦略
1. RSI(Relative Strength Index)を使った戦略 RSIで売られ過ぎが出たら買う 2. MACD(Moving Average Convergence/Divergence)を使った戦略 MACDがマイナス圏でゴールデンクロスが発生したら買い いずれの戦略も エントリーから2%の下落で損切り、 1%の上昇で半分利確とエントリー価格に撤退指値、 2%上昇したら全利確
勝率の計算:
calculate_win_rate(df)関数で、利益がプラスのトレード数をカウントし、総トレード数で割って勝率を算出します。
勝ちトレードの数、総トレード数、そして勝率が表示されます。
バックテスト結果:
終了時に、勝率、勝ちトレード数、総取引数がコンソールに表示されます。
例: 勝率: 60.00% (勝ち: 6, 総取引数: 10) のように出力されます。
グラフ描画:
価格推移と累積利益率のグラフを描画します。
import pandas as pd
import yfinance as yf
import ta
import matplotlib.pyplot as plt
# テクニカル指標の設定
def apply_technical_indicators(df):
# RSIを計算 (14日間)
df['RSI'] = ta.momentum.RSIIndicator(df['Close'], window=14).rsi()
# MACDを計算 (デフォルトの設定)
macd = ta.trend.MACD(df['Close'])
df['MACD'] = macd.macd()
df['MACD_signal'] = macd.macd_signal()
return df
# シンプルなトレード戦略
def trading_strategy(df):
df['position'] = 0 # トレードのポジション:1は買い、-1は売り、0はなし
df['buy_price'] = None
df['profit_pct'] = 0 # 利益率
entry_price = 0 # エントリーポジションの価格
for i in range(1, len(df)):
# RSI 戦略: RSIが30以下の場合に買い(売られ過ぎ)
if df['RSI'][i] < 30 and df['position'][i-1] == 0:
df['position'][i] = 1 # 買いエントリー
df['buy_price'] = df['Close'][i]
entry_price = df['Close'][i]
# MACD 戦略: MACDがマイナス圏でゴールデンクロスの場合に買い
elif df['MACD'][i-1] < 0 and df['MACD'][i] > df['MACD_signal'][i] and df['position'][i-1] == 0:
df['position'][i] = 1 # 買いエントリー
df['buy_price'] = df['Close'][i]
entry_price = df['Close'][i]
# 利確・損切り条件
elif df['position'][i-1] == 1:
# 損切り: 2% 下落
if df['Close'][i] < entry_price * 0.98:
df['profit_pct'][i] = (df['Close'][i] - entry_price) / entry_price # 損切りの利益率
df['position'][i] = 0 # ポジションを閉じる
entry_price = 0
# 利確: 1% 上昇で全利確
elif df['Close'][i] > entry_price * 1.01:
df['profit_pct'][i] = (df['Close'][i] - entry_price) / entry_price # 利確の利益率
df['position'][i] = 0 # 全利確
entry_price = 0
else:
df['position'][i] = df['position'][i-1] # 前回のポジションを保持
df['profit_pct'][i] = 0 # 利益は発生していない
return df
# 勝率計算
def calculate_win_rate(df):
# 勝ちトレード(利益がプラス)と全トレードをカウント
winning_trades = df[df['profit_pct'] > 0]['profit_pct'].count()
total_trades = df[df['profit_pct'] != 0]['profit_pct'].count()
# 勝率を計算
win_rate = (winning_trades / total_trades) * 100 if total_trades > 0 else 0
return win_rate, winning_trades, total_trades
# データ取得とバックテスト
def backtest_strategy(ticker):
# 過去データを取得(過去1年分)
df = yf.download(ticker, period="1y")
# テクニカル指標を追加
df = apply_technical_indicators(df)
# トレード戦略を適用
df = trading_strategy(df)
# ポジションの履歴と利益率
print(df[['Close', 'RSI', 'MACD', 'MACD_signal', 'position', 'profit_pct']].tail(20))
return df
# 利益率とパフォーマンスをプロット
def plot_performance(df):
# 累積利益率の計算
df['cumulative_return'] = (1 + df['profit_pct']).cumprod() - 1
plt.figure(figsize=(14, 7))
# 価格チャート
plt.subplot(2, 1, 1)
plt.plot(df.index, df['Close'], label='Close Price', color='blue', alpha=0.5)
plt.title('Price and Performance Over Last 1 Year')
plt.xlabel('Date')
plt.ylabel('Close Price')
plt.grid(True)
# 利益率チャート
plt.subplot(2, 1, 2)
plt.plot(df.index, df['cumulative_return'], label='Cumulative Return', color='green', alpha=0.7)
plt.title('Cumulative Return Over Last 1 Year')
plt.xlabel('Date')
plt.ylabel('Cumulative Return (%)')
plt.grid(True)
plt.tight_layout()
plt.show()
# 実行
df = backtest_strategy('AAPL')
# 勝率計算
win_rate, winning_trades, total_trades = calculate_win_rate(df)
print(f"勝率: {win_rate:.2f}% (勝ち: {winning_trades}, 総取引数: {total_trades})")
# パフォーマンスと利益率をプロット
plot_performance(df)
バックテスト結果 勝率: 70.00% (勝ち: 7, 総取引数: 10)
まとめ
テクニカル分析の有名な指標でも単体で利用しても勝率は50%前後
複数の指標を組合せてトレードすると勝率は上昇することがわかりました
BOTでトレードする場合は、結果の検証を行いながら利用してみましょう