先日ボーナスが入りました。
最近は物欲がないので特にボーナスが出たからと言って買いたいものがないのですが、
パソコンの作業効率向上のためにモニターをもう一台買おうか悩んでいます。
それでは今回も作業進めていきます。
はじめに
前回は、MT4から出力したバックテスト結果をPythonで読み込み、「零号機」の基本成績を分析しました。

総取引数、勝率、PF、平均利益・平均損失、最大ドローダウンなどを確認し、さらに月別損益も集計しました。
ただ、月別損益を数字だけで並べても、
「どの時期に大きく勝ち、どの時期に大きく負けているのか」
は少し分かりにくいです。
そこで今回は、前回作成した月別損益を棒グラフにして視覚化します。
数字の一覧からでは見えにくかった、零号機の成績の「ムラ」を観測してみます。
今回やること
今回の処理はシンプルです。
月別損益を集計
↓
matplotlibで棒グラフを作成
↓
monthly_profit.pngとして保存
↓
利益月・損失月のばらつきを確認
Pythonでグラフを作成するために、今回はmatplotlibというライブラリを使います。
1.matplotlibを追加する
まず、WSLでUbuntuに入り、分析用フォルダへ移動します。
cd /mnt/c/Users/***/ea-analysis
そして、matplotlibを追加します。
uv add matplotlib
matplotlibは、Pythonでグラフを作成するための代表的なライブラリです。
今回のような棒グラフだけでなく、折れ線グラフや散布図なども作成できます。
2.matplotlibを読み込む
Python側では、次のコードを追加します。
import matplotlib.pyplot as plt
ここでは、
matplotlib.pyplot
を、
plt
という短い名前で使えるようにしています。
以降、
plt.figure()
plt.bar()
plt.savefig()
といった形でグラフを操作します。
3.月別損益を集計する
グラフに使うデータを作ります。
monthly_profit = (
trades
.groupby("年月")["損益"]
.sum()
.reset_index()
)
前回も使ったgroupby()です。
ここでは、
.groupby("年月")
で同じ年月の取引をまとめ、
["損益"]
で損益列を対象にして、
.sum()
で月ごとの損益を合計しています。
例えば、
2026-01
+500
-200
+300
という取引があれば、
2026-01 → +600円
として1か月分にまとめられます。
最後に、
.reset_index()
を使って、groupby()によってインデックスになった「年月」を、再び通常の列に戻しています。
これによって、集計結果は、
年月 損益
0 2015-01 15586.10
1 2015-02 -422.18
2 2015-03 -12471.63
のようなDataFrameになります。
このあとグラフを作成するときに、
monthly_profit["年月"]
monthly_profit["損益"]
と、それぞれの列を指定して利用できます。
4.グラフを作る領域を用意する
続いて、
plt.figure(
figsize=(14, 6)
)
でグラフを作成する領域を用意します。
figsizeはグラフの大きさです。
figsize=(14, 6)
なので、
横:14
縦:6
の比率で作成します。
今回のバックテストは10年以上あり、月数も多いため、横長のグラフにしています。
5.棒グラフを作成する
実際に棒グラフを作るのが、
plt.bar(
monthly_profit.index,
monthly_profit.values
)
です。
plt.bar()は棒グラフを作る関数です。
ここでは、
monthly_profit.index
を横軸、
monthly_profit.values
を縦軸にしています。
今回のmonthly_profitは、
年月 損益
2015-01 15586.10
2015-02 -422.18
2015-03 -12471.63
...
という構造なので、
横軸 → 年月
縦軸 → 月間損益
というグラフになります。
6.タイトルと軸の名前を付ける
続いて、
plt.title("Monthly Profit")
plt.xlabel("Month")
plt.ylabel("Profit")
で、グラフのタイトルと軸の名前を設定します。
それぞれ、
Monthly Profit
→ 月別損益
Month
→ 月
Profit
→ 損益
という意味です。
7.横軸の文字を90度回転する
月数が多いため、そのまま年月を表示すると文字同士が重なってしまいます。
そこで、
plt.xticks(
rotation=90
)
とします。
rotation=90は、
横軸の文字を90度回転する
という意味です。
これによって年月を縦向きに表示し、できるだけ読みやすくしています。
8.レイアウトを自動調整する
続いて、
plt.tight_layout()
を実行します。
これは、
グラフの文字やラベルが枠からはみ出さないように、自動的に余白を調整する
ための処理です。
今回のように横軸の文字を90度回転させる場合には特に役立ちます。
9.グラフを画像として保存する
完成したグラフを保存します。
plt.savefig(
"results/monthly_profit.png",
dpi=150
)
plt.savefig()は、
作成したグラフを画像ファイルとして保存する
ための関数です。
今回は、
results/monthly_profit.png
として保存します。
また、
dpi=150
で画像の解像度を指定しています。
10.グラフを閉じる
保存後には、
plt.close()
を実行します。
これは、作成したグラフを閉じる処理です。
今後、同じPythonプログラムの中で時間帯別・曜日別・保有時間別など複数のグラフを作成するため、前のグラフを閉じておきます。
実行結果
コードを実行すると、
results
└─ monthly_profit.png
が作成されました。
棒グラフにすると、数字だけを眺めていたときよりも、零号機の成績にかなりばらつきがあることが分かります。

分析
月別損益をグラフにすると、数字の一覧だけを見ていたときよりも、「零号機」の特徴がかなり分かりやすくなりました。
まず目につくのは、月によって損益のばらつきがかなり大きいことです。
多くの月では損益が0円付近から数千円程度の範囲に収まっていますが、その中に大きな利益を出した月、大きな損失を出した月が点在しています。
特にバックテスト前半には、約+29,000円の大きな利益を出した月がある一方で、約-18,000円の損失を出した月もあります。
その後の期間を見ても、+10,000円を超える利益月や、-10,000円を下回る損失月が時折発生しています。
つまり、零号機は毎月安定して少しずつ利益を積み上げるタイプというより、
「普段は比較的小さな損益を繰り返しながら、ときどき大きく勝ったり負けたりする」
という特徴がありそうです。
また、グラフ全体を見ると、特定の時期だけ一貫して利益が出ているわけでもありません。
利益月と損失月が入り交じりながら、長期間のバックテストでは最終的にプラスになっています。
前回の分析では、
- 勝率:61.86%
- PF:1.33
- 総損益:+223,494.50円
という結果でした。
しかし、今回のグラフを見ると、その約22万円の利益が均等に積み上がったわけではないことが分かります。
ここで気になるのが、
なぜ、これほど成績の良い月と悪い月が生まれるのか?
ということです。
このグラフだけでは、その原因までは分かりません。
時間帯による違いなのか、曜日による違いなのか。それとも、そのときの相場環境によるものなのか。
現時点で言えるのは、
「零号機の成績には、時期によって明確なムラがある」
ということまでです。
今回の完成コード
第4回までに作成したコードに、今回のグラフ作成処理を追加すると、ここまでのコードは次のようになります。
コード全文はこちら
import os
import pandas as pd
import matplotlib.pyplot as plt
# resultsフォルダが存在しない場合は作成
os.makedirs(
"results",
exist_ok=True
)
# CSV読み込み
df = pd.read_csv(
"/mnt/c/MT4/report.csv",
encoding="utf-8-sig"
)
# 決済済み取引(close)だけ抽出
trades = df[
df["取引種別"] == "close"
].copy()
# 日時を変換
trades["時間"] = pd.to_datetime(
trades["時間"],
format="%Y.%m.%d %H:%M"
)
# 年月列を作成
trades["年月"] = (
trades["時間"]
.dt.strftime("%Y-%m")
)
# 基本集計
total_trades = len(trades)
wins = trades[
trades["損益"] > 0
]
losses = trades[
trades["損益"] < 0
]
# 勝ち数・負け数
win_count = len(wins)
loss_count = len(losses)
# 勝率
win_rate = (
win_count
/ total_trades
* 100
)
# 利益合計・損失合計
gross_profit = wins["損益"].sum()
gross_loss = losses["損益"].sum()
# プロフィットファクタ
profit_factor = (
gross_profit / abs(gross_loss)
if gross_loss != 0
else float("nan")
)
# 損益・平均利益・平均損失
total_profit = trades["損益"].sum()
average_profit = wins["損益"].mean()
average_loss = losses["損益"].mean()
# 最大ドローダウン
trades["過去最高残高"] = (
trades["残高"].cummax()
)
trades["ドローダウン"] = (
trades["残高"]
- trades["過去最高残高"]
)
max_balance_drawdown = (
trades["ドローダウン"].min()
)
# 基本分析結果を表示
print("===== EA分析結果 =====")
print(f"総取引数: {total_trades}")
print(f"勝ち取引: {win_count}")
print(f"負け取引: {loss_count}")
print(f"勝率: {win_rate:.2f}%")
print(f"総損益: {total_profit:.2f}")
print(f"総利益: {gross_profit:.2f}")
print(f"総損失: {gross_loss:.2f}")
print(f"PF: {profit_factor:.2f}")
print(f"平均利益: {average_profit:.2f}")
print(f"平均損失: {average_loss:.2f}")
print(
f"最大ドローダウン: "
f"{max_balance_drawdown:.2f}"
)
print(
f"最終残高: "
f"{trades['残高'].iloc[-1]:.2f}"
)
# 月別損益
monthly_profit = (
trades
.groupby("年月")["損益"]
.sum()
.reset_index()
)
print("\n===== 月別損益 =====")
print(monthly_profit)
# ==============================
# 月別損益グラフ
# ==============================
plt.figure(
figsize=(14, 6)
)
plt.bar(
monthly_profit["年月"],
monthly_profit["損益"]
)
plt.title("Monthly Profit")
plt.xlabel("Month")
plt.ylabel("Profit")
plt.xticks(
rotation=90
)
plt.tight_layout()
plt.savefig(
"results/monthly_profit.png",
dpi=150
)
plt.close()
print(
"月別損益グラフを "
"results/monthly_profit.png "
"として保存しました。"
)
次回 ― 時間帯別に分析する
月別損益を見ることで、
「成績には時期によってムラがある」
ことが分かりました。
では、もっと細かく見るとどうでしょうか。
次回は、
「どの時間帯で勝ち、どの時間帯で負けているのか」
を分析します。
零号機が得意な時間帯、苦手な時間帯が存在するのか。
さらに一段細かく観測していきます。

おまけ
今、「知って得する、すごい法則77」という本を読んでいます。
1つの法則につき数ページなので、サクサク読めます。
知っている法則も多いですが、ある程度体系的にまとまっているので、意味が逆の法則を場面場面で利用し分ける目線など面白いです。
これを実務で利用するぞ!というより、読んでいて面白い本です。
次の記事

コメント