😸

PythonでFXのユロドルアノマリーを検証

2023/10/21に公開

値動きの特徴

import pandas as pd
import MetaTrader5 as mt5
from datetime import timedelta
import seaborn as sns
import matplotlib.pyplot as plt

# MT5への接続
mt5.initialize()

def fetch_and_prepare(symbol, timeframe, count, timezone_hours, ratio_calculation):
    # データの取得
    rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, count)

    # DataFrameに変換
    df = pd.DataFrame(rates)

    # 日時をPandasの日時形式に変換し、GMT+9に変換
    df['time'] = pd.to_datetime(df['time'], unit='s') + timedelta(hours=timezone_hours)

    df[ratio_calculation.name] = ratio_calculation(df)

    return df

def high_low_ratio(df):
    return (df['high'] - df['low']) / df['low']

def close_open_ratio(df):
    return (df['close'] - df['open']) / df['open']

def plot_avg_return(df, column_name):
    # インデックスを日付に変換
    df.set_index('time', inplace=True)

    # 5分ごとの平均リターンを計算
    df['5min_avg_return'] = df[column_name].rolling(window=5).mean()

    # 時刻をグループ化して平均を計算
    grouped_df = df.groupby(df.index.time).mean()

    # 時刻を文字列に変換
    grouped_df.index = grouped_df.index.astype(str)

    # グラフの作成
    plt.figure(figsize=(50, 10))
    sns.barplot(x=grouped_df.index, y=grouped_df['5min_avg_return'])
    plt.xlabel('Time')
    plt.ylabel('5min Average Return')
    plt.title('5-minute Average Return (Grouped by Time)')

    # X軸のラベルを斜めに表示
    plt.xticks(rotation=90)

    plt.show()

def fetch_and_prepare(symbol, timeframe, count, timezone_hours, ratio_calculation, column_name):
    # データの取得
    rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, count)

    # DataFrameに変換
    df = pd.DataFrame(rates)

    # 日時をPandasの日時形式に変換し、GMT+9に変換
    df['time'] = pd.to_datetime(df['time'], unit='s') + timedelta(hours=timezone_hours)

    df[column_name] = ratio_calculation(df)

    return df

# 読み込む通貨ペアと時間枠、データの件数を指定
symbol = 'EURUSDm'
timeframe = mt5.TIMEFRAME_M5
count = 100000
timezone_hours = 9

df = fetch_and_prepare(symbol, timeframe, count, timezone_hours, high_low_ratio, 'high_low_ratio')
plot_avg_return(df, 'high_low_ratio')

df = fetch_and_prepare(symbol, timeframe, count, timezone_hours, close_open_ratio, 'close_open_ratio')
plot_avg_return(df, 'close_open_ratio')

ストラテジーテスターの解析

import pandas as pd
import matplotlib.pyplot as plt

def extract_deals_from_html(file_path):
    df = pd.read_html(file_path)[1]
    index = df.index[df.iloc[:, 0] == '約定'].tolist()[0]
    deals = df.iloc[index+1:-2].reset_index(drop=True)
    deals.columns = deals.iloc[0]
    return deals.iloc[2:].reset_index(drop=True)

def preprocess_deals(deals):
    deals['時間'] = pd.to_datetime(deals['時間'])
    columns_to_convert = {
        '約定': int,
        '注文': int,
        '数量': float,
        '価格': float,
        '損益': lambda x: float(x.replace(' ', '')),
        '残高': lambda x: float(x.replace(' ', ''))
    }
    for col, dtype in columns_to_convert.items():
        deals[col] = deals[col].apply(dtype)
    return deals

def rename_columns(deals):
    column_mapping = {
        '時間': 'Time',
        '約定': 'Transaction',
        '銘柄': 'Stock',
        'タイプ': 'Type',
        '新規・決済': 'EntryOrExit',
        '数量': 'Quantity',
        '価格': 'Price',
        '注文': 'Order',
        '手数料': 'Fee',
        'スワップ': 'Swap',
        '損益': 'ProfitOrLoss',
        '残高': 'Balance',
        'コメント': 'Comment'
    }
    return deals.rename(columns=column_mapping)

def plot_daily_profit_or_loss(deals, start_date=None, end_date=None):
    if start_date:
        deals = deals[deals['Time'] >= start_date]
    if end_date:
        deals = deals[deals['Time'] <= end_date]
    
    deals['day'] = deals['Time'].dt.day
    daily_profit_loss = deals.groupby('day')['ProfitOrLoss'].sum()
    plt.figure(figsize=(10,6))
    daily_profit_loss.plot(kind='bar')
    plt.title('Daily Profit or Loss')
    plt.xlabel('Day')
    plt.ylabel('Profit or Loss')
    plt.grid(axis='y')
    plt.tight_layout()
    plt.show()

# Main execution
file_path = "ReportTester-76433893.html"
deals = extract_deals_from_html(file_path)
deals = preprocess_deals(deals)
deals = rename_columns(deals)

# グラフの表示
plot_daily_profit_or_loss(deals) # 期間指定なしの場合
plot_daily_profit_or_loss(deals, start_date="2023-07-01", end_date="2023-10-21")  # 期間を指定する場合

参考
https://qiita.com/aisaki180507/items/b9f0c086ba30f72dd195

Discussion