RSIとMDCDとボリンジャーバンドの全てで売買シグナルが出た時だけビットコインを自動売買するシュミレーションだと、過去2年半で2.5倍になったけど、ガチホでも2倍になってるから上げ相場だっただけ?初期資金15万円からの、ガチホで30万。自動売買で38万。
Final balance after backtest: 379782.35000000003 JPY
Final balance with buy & hold: 300608.6242586295 JPY
type price balance_jpy btc timestamp
0 buy 4995522.0 150000.00 0.03 2022-01-06 03:15:00+00:00
1 sell 4703955.0 141252.99 0.03 2022-02-04 23:30:00+00:00
2 buy 4771136.0 141252.99 0.02 2022-02-17 18:00:00+00:00
3 sell 4508856.0 136007.39 0.02 2022-02-23 13:00:00+00:00
4 buy 4478192.0 136007.39 0.03 2022-03-10 13:30:00+00:00
5 sell 5821204.0 176297.75 0.03 2022-03-28 05:00:00+00:00
6 buy 4812600.0 176297.75 0.03 2022-04-26 20:00:00+00:00
7 sell 4097133.0 154833.74 0.03 2022-06-06 08:00:00+00:00
8 buy 2550191.0 154833.74 0.06 2022-06-30 13:30:00+00:00
9 sell 2695095.0 163527.98 0.06 2022-07-04 15:00:00+00:00
10 buy 3142582.0 163527.98 0.05 2022-08-17 19:00:00+00:00
11 sell 2977818.0 155289.78 0.05 2022-09-09 10:30:00+00:00
12 buy 2786318.0 155289.78 0.05 2022-09-18 21:00:00+00:00
13 sell 2393444.0 135646.08 0.05 2022-11-14 13:00:00+00:00
14 buy 2294350.0 135646.08 0.05 2022-12-01 21:00:00+00:00
15 sell 2947745.0 168315.83 0.05 2023-01-21 08:00:00+00:00
16 buy 2967800.0 168315.83 0.05 2023-03-09 07:15:00+00:00
17 sell 3767196.0 208285.63 0.05 2023-03-29 12:45:00+00:00
18 buy 4104415.0 208285.63 0.05 2023-07-24 14:45:00+00:00
19 sell 4202583.0 213194.03 0.05 2023-10-02 03:30:00+00:00
20 buy 4067791.0 213194.03 0.05 2023-10-03 18:45:00+00:00
21 sell 5592913.0 289450.13 0.05 2023-11-09 12:15:00+00:00
22 buy 6195638.0 289450.13 0.04 2024-01-12 22:00:00+00:00
23 sell 8299190.0 373592.21 0.04 2024-02-27 01:30:00+00:00
24 buy 10061762.0 373592.21 0.03 2024-04-02 08:45:00+00:00
25 sell 10129191.0 375615.08 0.03 2024-04-19 11:30:00+00:00
26 buy 9547483.0 375615.08 0.03 2024-04-30 14:00:00+00:00
27 sell 9600048.0 377192.03 0.03 2024-05-03 20:15:00+00:00
28 buy 10600000.0 377192.03 0.03 2024-06-11 08:00:00+00:00
29 sell 10686344.0 379782.35 0.00 2024-06-12 20:45:00+00:00
Total trades: 30
Winning trades: 10
Win rate: 66.67%
Total profit: 229782.35000000003 JPY
Average profit: 15318.823333333336 JPY
Max profit: 84142.08000000002 JPY
Min profit: -21464.01000000001 JPY
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
import pandas as pd # pandasライブラリをインポート import ta # テクニカル指標計算のためのライブラリをインポート import matplotlib.pyplot as plt # グラフ描画のためのライブラリをインポート # CSVファイルからデータを読み込み def fetch_ohlcv(file_path): df = pd.read_csv(file_path) # CSVファイルを読み込み、データフレームを作成 df['timestamp'] = pd.to_datetime(df['timestamp']) # 'timestamp'列を日時型に変換 df.set_index('timestamp', inplace=True) # 'timestamp'列をインデックスに設定 return df # データフレームを返す # テクニカル指標の計算 def calculate_indicators(df): df['sma'] = ta.trend.sma_indicator(df['close'], window=20) # 20期間の単純移動平均を計算 df['rsi'] = ta.momentum.rsi(df['close'], window=14) # 14期間のRSIを計算 df['macd'] = ta.trend.macd(df['close']) # MACDを計算 df['macd_signal'] = ta.trend.macd_signal(df['close']) # MACDシグナルラインを計算 bb = ta.volatility.BollingerBands(df['close']) # ボリンジャーバンドを計算 df['bb_upper'], df['bb_middle'], df['bb_lower'] = bb.bollinger_hband(), bb.bollinger_mavg(), bb.bollinger_lband() # ボリンジャーバンドの上限、中間、下限を設定 return df # データフレームを返す # バックテスト def backtest(df): initial_balance_jpy = 150000 # 初期資金(JPY) balance_jpy = initial_balance_jpy # 現金残高(JPY) btc = 0 # 初期BTC保有量 trades = [] # トレード履歴を保持するリスト min_trade_btc = 0.01 # 最低取引単位(BTC) for i in range(len(df) - 1): # データフレームの行数分ループ # 買いシグナルの条件 if ( df['rsi'].iloc[i] < 30 # RSIが30未満で、売られ過ぎを示す and df['macd'].iloc[i] > df['macd_signal'].iloc[i] # MACDがシグナルラインを上回り、上昇トレンドを示す and df['close'].iloc[i] < df['bb_lower'].iloc[i] # 現在の価格がボリンジャーバンドの下限を下回り、過剰に売られていることを示す and balance_jpy >= df['close'].iloc[i] * min_trade_btc # 残高が最低取引単位の購入に十分であることを確認 ): btc_to_buy = (balance_jpy // (df['close'].iloc[i] * min_trade_btc)) * min_trade_btc # 購入可能なBTC量を計算 if btc_to_buy >= min_trade_btc: # 最低取引単位を確認 btc += btc_to_buy # BTCを購入 spent_jpy = btc_to_buy * df['close'].iloc[i] # 購入に使用したJPYを計算 trades.append({ # トレード情報を記録 'type': 'buy', 'price': df['close'].iloc[i], 'balance_jpy': balance_jpy, 'btc': btc, 'timestamp': df.index[i] }) balance_jpy -= spent_jpy # 現金残高から購入額を減算 # 売りシグナルの条件 elif ( df['rsi'].iloc[i] > 70 # RSIが70以上で、買われ過ぎを示す and df['macd'].iloc[i] < df['macd_signal'].iloc[i] # MACDがシグナルラインを下回り、下降トレンドを示す and df['close'].iloc[i] > df['bb_upper'].iloc[i] # 現在の価格がボリンジャーバンドの上限を上回り、過剰に買われていることを示す and btc >= min_trade_btc # 最低取引単位を確認 ): balance_jpy += btc * df['close'].iloc[i] # 現在の価格でBTCを売却 trades.append({ # トレード情報を記録 'type': 'sell', 'price': df['close'].iloc[i], 'balance_jpy': balance_jpy, 'btc': btc, 'timestamp': df.index[i] }) btc = 0 # BTC保有量を0に設定 # 最後のトレードの後に余ったBTCを現金化 if btc >= min_trade_btc: balance_jpy += btc * df['close'].iloc[-1] trades.append({ # トレード情報を記録 'type': 'sell', 'price': df['close'].iloc[-1], 'balance_jpy': balance_jpy, 'btc': 0, 'timestamp': df.index[-1] }) btc = 0 # BTC保有量を0に設定 final_balance_jpy = balance_jpy + (btc * df['close'].iloc[-1] if btc >= min_trade_btc else 0) # 最終残高を計算 return final_balance_jpy, trades # 最終残高とトレード履歴を返す # Buy & Holdの成績計算 def buy_and_hold(df): initial_balance_jpy = 150000 # 初期資金(JPY) btc = initial_balance_jpy / df['close'].iloc[0] # 初期価格でBTCを購入 final_balance_jpy = btc * df['close'].iloc[-1] # 最終残高を計算 return final_balance_jpy, btc # 最終残高とBTC保有量を返す # グラフの作成 def plot_trades(trades_df, df, buy_hold_btc): plt.figure(figsize=(14, 7)) # グラフのサイズを設定 # ビットコイン価格のプロット plt.plot(df.index, df['close'], label='BTC Price', color='blue') # ビットコイン価格を青色でプロット # Buy & Holdのプロット plt.plot(df.index, buy_hold_btc * df['close'], label='Buy & Hold Balance', color='orange', linestyle='dashed') # Buy & Holdの残高をオレンジ色の破線でプロット # トレードシグナルのプロット buy_signals = trades_df[trades_df['type'] == 'buy'] # 買いシグナルを抽出 sell_signals = trades_df[trades_df['type'] == 'sell'] # 売りシグナルを抽出 plt.scatter(buy_signals['timestamp'], buy_signals['price'], marker='^', color='green', label='Buy Signal', alpha=1) # 買いシグナルを緑色の三角形でプロット plt.scatter(sell_signals['timestamp'], sell_signals['price'], marker='v', color='red', label='Sell Signal', alpha=1) # 売りシグナルを赤色の逆三角形でプロット # トレード戦略のバランスのプロット plt.plot(trades_df['timestamp'], trades_df['balance_jpy'], label='Trade Strategy Balance', color='purple', linestyle='dotted') # トレード戦略の残高を紫色の点線でプロット plt.xlabel('Time') # x軸のラベルを設定 plt.ylabel('Price / Balance') # y軸のラベルを設定 plt.title('Trade Signals, BTC Price, and Balance Over Time') # グラフのタイトルを設定 plt.legend() # 凡例を表示 plt.show() # グラフを表示 # メイン関数 def main(): file_path = 'historical_data.csv' # ローカルのCSVファイルのパス df = fetch_ohlcv(file_path) # データを読み込み df = calculate_indicators(df) # テクニカル指標を計算 final_balance_jpy, trades = backtest(df) # バックテストを実行 buy_hold_balance_jpy, buy_hold_btc = buy_and_hold(df) # Buy & Holdの成績を計算 print(f'Final balance after backtest: {final_balance_jpy} JPY') # バックテスト後の最終残高を表示 print(f'Final balance with buy & hold: {buy_hold_balance_jpy} JPY') # Buy & Holdの最終残高を表示 # トレード履歴を表示 trades_df = pd.DataFrame(trades) # トレード履歴をデータフレームに変換 print(trades_df) # トレード履歴を表示 # トレード回数と勝率を計算 buy_trades = trades_df[trades_df['type'] == 'buy'].reset_index(drop=True) # 買いトレードを抽出 sell_trades = trades_df[trades_df['type'] == 'sell'].reset_index(drop=True) # 売りトレードを抽出 # トレード回数が一致しない場合の警告 if len(buy_trades) != len(sell_trades): print("Warning: Number of buy and sell trades do not match. Ignoring last unmatched trade.") # 警告メッセージを表示 buy_trades = buy_trades[:len(sell_trades)] # 不一致のトレードを無視 sell_trades = sell_trades[:len(buy_trades)] # 不一致のトレードを無視 profits = sell_trades['balance_jpy'].values - buy_trades['balance_jpy'].values # 各トレードの利益を計算 winning_trades = profits[profits > 0] # 勝ちトレードを抽出 losing_trades = profits[profits <= 0] # 負けトレードを抽出 win_rate = (len(winning_trades) / len(sell_trades)) * 100 if len(sell_trades) > 0 else 0 # 勝率を計算 # 追加の利益分析 total_profit = profits.sum() # 総利益を計算 average_profit = profits.mean() # 平均利益を計算 max_profit = profits.max() # 最大利益を計算 min_profit = profits.min() # 最小利益を計算 print(f'Total trades: {len(trades)}') # トレード回数を表示 print(f'Winning trades: {len(winning_trades)}') # 勝ちトレード数を表示 print(f'Win rate: {win_rate:.2f}%') # 勝率を表示 print(f'Total profit: {total_profit} JPY') # 総利益を表示 print(f'Average profit: {average_profit} JPY') # 平均利益を表示 print(f'Max profit: {max_profit} JPY') # 最大利益を表示 print(f'Min profit: {min_profit} JPY') # 最小利益を表示 # トレードのグラフ表示 plot_trades(trades_df, df, buy_hold_btc) # トレード履歴のグラフを作成 if __name__ == "__main__": main() # メイン関数を実行 |