
PythonとMQL5によるポートフォリオ最適化
はじめに
取引戦略を刷新し、リスクを最小限に抑えつつリターンを最大化するための2つの革新的なポートフォリオ最適化プログラムを紹介します。最初のPythonベースのソリューションでは、pandas、Numpy、cvxpyなどの高度なライブラリを活用し、MetaTrader 5との統合により、過去データを分析して最適な資産配分をおこない、Matplotlibで結果を可視化します。次に、MQL5を使用した同様の実装では、MetaTrader 5のネイティブ機能を活かし、トレーダーの好む取引環境でシームレスな体験を提供します。両プログラムは、クオンツファイナンスとテクノロジーの最先端を体現しており、トレーダーは進化し続ける市場環境に対応したデータ主導の意思決定をおこなうための強力なツールを手にすることができます。
なぜポートフォリオ最適化が必要なのか?
ポートフォリオ最適化プログラムは、複雑さが増し、変動の激しい現代の投資環境で、効率的なリスク調整後リターンを追求するために不可欠なツールです。これらのプログラムは、数学的モデルと高い計算能力を駆使し、投資家や金融専門家がリスク許容度や投資目標に合わせたデータ主導の意思決定をおこなうのを支援します。過去の膨大なデータを体系的に分析し、マーケットトレンドや資産間の相関関係を評価することで、ポートフォリオ全体のリスクを最小化しつつ、最大のリターンを追求する最適な資産配分を決定します。
この科学的なポートフォリオ構築アプローチは、従来の投資戦略にしばしば見られる人間の偏見や感情的な意思決定を軽減する効果があります。さらに、ポートフォリオ最適化プログラムは動的なリバランスを可能にし、投資家が変化する市場状況に迅速に対応しながら、長期的な財務目標との整合性を維持できるよう支援します。世界経済が密接に相互接続し、情報が急速に伝わる時代において、これらの洗練されたツールは投資家に競争優位をもたらし、不確実性を乗り越えつつ多様な資産クラスの機会を最大限に活用できるようにします。最終的には、より堅牢で回復力のある投資戦略の構築を促進します。
なぜPythonを使う必要があるのか?
Pythonは、戦略やアイデアを素早く試すための優れた手段です。大規模なコミュニティに支えられ、実行スピードも速いです。さらに、MetaTrader 5ライブラリを活用すれば、データのダウンロードや取引の実行も可能です。まずPythonを使用することで、考え方が一貫しているか、異なる銘柄で口座の割合をどのように調整すべきかを迅速に検証できます。
以下は、これから使用するpythonスクリプトです。
# Import necessary libraries import MetaTrader5 as mt5 import pandas as pd import numpy as np import cvxpy as cp import matplotlib.pyplot as plt from datetime import datetime # Function to obtain historical data from MT5 def get_mt5_data(symbols, from_date, to_date): # Establish connection with MetaTrader 5 if not mt5.initialize(): print("Error: Could not connect to MetaTrader 5") mt5.shutdown() return None data = {} for symbol in symbols: # Get historical price data rates = mt5.copy_rates_range(symbol, mt5.TIMEFRAME_D1, from_date, to_date) if rates is not None: # Convert to Pandas DataFrame df = pd.DataFrame(rates) df['time'] = pd.to_datetime(df['time'], unit='s') df.set_index('time', inplace=True) df.drop(['tick_volume', 'spread', 'real_volume'], axis=1, inplace=True) # Calculate daily returns df['return'] = df['close'].pct_change().fillna(0) # Save in the data dictionary data[symbol] = df # Close the connection with MetaTrader 5 mt5.shutdown() return data # Function to optimize the portfolio def optimize_portfolio(data): symbols = list(data.keys()) n_assets = len(symbols) # Find the minimum data length among all assets min_length = min(len(data[symbol]) for symbol in symbols) # Adjust and normalize returns returns = np.zeros((min_length, n_assets)) for i, symbol in enumerate(symbols): # Adjust data length df = data[symbol].iloc[:min_length] returns[:, i] = df['return'].values # Calculate covariance matrix and expected returns cov_matrix = np.cov(returns, rowvar=False) expected_returns = np.mean(returns, axis=0) # Optimization variables weights = cp.Variable(n_assets) risk = cp.quad_form(weights, cov_matrix) objective = cp.Maximize(expected_returns @ weights - 0.5 * risk) # Constraints constraints = [cp.sum(weights) == 1, weights >= 0] # Solve the optimization problem prob = cp.Problem(objective, constraints) prob.solve() # Display optimization results print("\nOptimization Results:") for i, symbol in enumerate(symbols): print(f"{symbol}: {weights.value[i]}") # Calculate minimum variance and expected return for the portfolio min_variance = cp.sqrt(cp.quad_form(weights.value, cov_matrix)).value expected_return_portfolio = expected_returns @ weights.value print(f"\nExpected portfolio return: {expected_return_portfolio:.4f}") print(f"Minimum portfolio variance: {min_variance:.4f}") return symbols, weights.value # Function to visualize results def visualize_results(symbols, weights): # Plot weights of each asset in the portfolio plt.figure(figsize=(10, 6)) plt.bar(symbols, weights, color='blue') plt.xlabel('Assets') plt.ylabel('Weights') plt.title('Asset Weights in Optimized Portfolio') plt.show() # Execute the main script if __name__ == "__main__": # Define parameters symbols = ["EURUSD", "GBPUSD", "#AMZN", "#AAPL"] # Asset symbols from_date = datetime(2023, 1, 1) # Start date to_date = datetime(2023, 12, 31) # End date # Get historical data from MT5 print(f"Obtaining historical data from {from_date} to {to_date}...") data = get_mt5_data(symbols, from_date, to_date) if data: # Optimize the portfolio symbols, weights = optimize_portfolio(data) # Visualize the results visualize_results(symbols, weights)
これが結果です。
Obtaining historical data from 2023-01-01 00:00:00 to 2023-12-31 00:00:00... Optimization Results: EURUSD: 1.9303305369616842e-23 GBPUSD: 1.9417113191106993e-23 #AMZN: 1.0 #AAPL: -1.3370355361690525e-23 Expected portfolio return: 0.0025 Minimum portfolio variance: 0.0205
そしてこれがグラフです。
この結果は、現在アマゾンのみに投資するよう指示していますが、スクリプトに戦略を追加することで、値動きに応じて他の銘柄にも投資するように変更できます。
この目的を達成するために、スクリプトに以下を追加します(ここでは2つの移動平均線が交差するシンプルな戦略を使用)。
# Function to apply the moving average crossover strategy def apply_sma_strategy(data, short_window=12, long_window=26): for symbol, df in data.items(): df['SMA_50'] = df['close'].rolling(window=short_window).mean() df['SMA_200'] = df['close'].rolling(window=long_window).mean() df['signal'] = 0 df.loc[df.index[short_window:], 'signal'] = np.where( df.loc[df.index[short_window:], 'SMA_50'] > df.loc[df.index[short_window:], 'SMA_200'], 1, 0 ) df['position'] = df['signal'].shift(1).fillna(0) return data # Function to adjust returns according to the strategy def adjust_returns(data): for symbol, df in data.items(): df['adjusted_return'] = df['return'] * df['position'] return data
そして、メインにこれも加えます。
# Apply the moving average crossover strategy data = apply_sma_strategy(data) # Adjust returns according to the strategy data = adjust_returns(data)
結果はこのように表示されます。
Obtaining historical data from 2023-01-01 00:00:00 to 2023-12-31 00:00:00... Optimization Results: EURUSD: -5.669275045708089e-25 GBPUSD: 5.494697501444607e-23 #AMZN: 1.0 #AAPL: -5.59465620602481e-23 Expected portfolio return: 0.0006 Minimum portfolio variance: 0.0151
いくつかの小さな変化はありましたが、全体的な結果はほぼ同じです。
というのも、AMZNはその間ずっと巨大なトレンドを持っていたからです。
このことを認識し、トレンドが止まるのを待つ必要がありますが、リスク管理がなぜそれほど重要なのかを理解できます。
MQL5スクリプト
ここまで、Pythonでこのリスク管理を開発する方法を見てきましたが、MQL5の方がより正確なので、今度は同じスクリプトをMQL5で再現してみましょう。
これがスクリプトです。
//+------------------------------------------------------------------+ //| optimizacion_carteras.mq5 | //| Copyright 2024, Javier Santiago Gaston de Iriarte Cabrera. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" // Define the assets to consider string symbols[] = {"EURUSD", "GBPUSD", "#AAPL", "#AMZN"}; // Date parameters to obtain historical data datetime from_date = D'2023.01.01 00:00'; datetime to_date = D'2024.01.01 00:00'; //+------------------------------------------------------------------+ //| Function to obtain historical data from MetaTrader 5 | //+------------------------------------------------------------------+ void obtenerDatosHistoricos(string symbol, datetime from, datetime to, double &out[][6]) { // Declare an array to store the historical rates MqlRates rates[]; // Copy historical data for the specified symbol and date range int copied = CopyRates(symbol, PERIOD_D1, from, to, rates); // Check if data copying was successful if(copied <= 0) Print("Failed to copy price data ", GetLastError()); else Print("Copied ", ArraySize(rates), " bars"); // Resize the output array to match the size of copied data ArrayResize(out, copied); Print("Copied ", copied, " data points for ", symbol); // Transfer data to the output array for(int i = 0; i < copied; i++) { out[i][0] = (double)rates[i].time; out[i][1] = rates[i].open; out[i][2] = rates[i].high; out[i][3] = rates[i].low; out[i][4] = rates[i].close; out[i][5] = (double)rates[i].tick_volume; } } //+------------------------------------------------------------------+ //| Function to calculate daily returns | //+------------------------------------------------------------------+ void calcularRendimientos(double &data[][6], double &returns[]) { // Determine the number of data points int total = ArrayRange(data, 0); // Resize the returns array to accommodate the calculated returns ArrayResize(returns, total - 1); Print("Calculating returns for ", total, " data points"); // Initialize variables to track maximum and minimum returns double max_return = -DBL_MAX; double min_return = DBL_MAX; int problematic_index = -1; int valid_returns_count = 0; // Iterate through the data points to calculate returns for(int i = 1; i < total; i++) { // Ensure the previous closing price is not zero to avoid division by zero if(data[i - 1][4] != 0.0) { // Calculate the return as the percentage change in closing prices double retorno = (data[i][4] - data[i - 1][4]) / data[i - 1][4]; returns[i - 1] = retorno; valid_returns_count++; // Update maximum and minimum returns if applicable if(retorno > max_return) max_return = retorno; if(retorno < min_return) min_return = retorno; // Identify and log suspicious returns if(MathAbs(retorno) > 1.0) { Print("Suspicious return at index ", i, ": ", retorno); Print("Data[", i - 1, "][4] = ", data[i - 1][4], ", Data[", i, "][4] = ", data[i][4]); problematic_index = i; } // Periodically print return values for verification if(i % 50 == 0 || i == total - 1) { Print("Return for index ", i - 1, ": ", retorno); } } else { // If the previous closing price is zero, set the return to zero returns[i - 1] = 0.0; Print("Zero price found at index ", i - 1); } } // Print the maximum and minimum returns Print("Max return: ", max_return, ", Min return: ", min_return); // Log the index of any problematic returns if(problematic_index != -1) { Print("Problematic return found at index: ", problematic_index); } } //+------------------------------------------------------------------+ //| Main function | //+------------------------------------------------------------------+ void OnStart() { // Declare arrays to store historical data and returns double data[][6]; double returns[]; // Loop through each symbol to obtain historical data and calculate returns for(int i = 0; i < ArraySize(symbols); i++) { obtenerDatosHistoricos(symbols[i], from_date, to_date, data); // Determine the size of the data array int data_size = ArraySize(data); Print("Data size for ", symbols[i], ": ", data_size); // Ensure there is enough data to calculate returns if(data_size > 1 && ArrayRange(data, 1) == 6) { calcularRendimientos(data, returns); int returns_size = ArraySize(returns); Print("Returns size for ", symbols[i], ": ", returns_size); // Initialize variables to calculate the expected return and variance double sum_returns = 0; int valid_returns = 0; // Sum the valid returns and count them for(int j = 0; j < returns_size; j++) { if(MathIsValidNumber(returns[j]) && MathAbs(returns[j]) <= 1.0) { sum_returns += returns[j]; valid_returns++; } else { Print("Invalid or extreme return at index ", j, ": ", returns[j]); } } // Calculate the mean return double mean_return = (valid_returns > 0) ? sum_returns / valid_returns : 0; // Calculate the variance of the returns double variance = 0; for(int j = 0; j < valid_returns; j++) { if(MathIsValidNumber(returns[j]) && MathAbs(returns[j]) <= 1.0) { variance += MathPow(returns[j] - mean_return, 2); } } variance = (valid_returns > 0) ? variance / valid_returns : 0; // Display the results in the console Print("Results for ", symbols[i]); Print("Expected return: ", mean_return); Print("Variance: ", variance); Print("Sum of returns: ", sum_returns); Print("Valid returns: ", valid_returns, " out of ", returns_size); Print("-----------------------"); } else { // Log if there were insufficient data or an incorrect data format Print("Could not obtain enough data for ", symbols[i], " or the data format is incorrect"); Print("-----------------------"); } } }
まず、スクリプトは、銘柄で表される考慮すべきアセットのリストを定義します。また、履歴データを取得するための日付範囲を設定し、開始日と終了日を指定します。
関数obtenerDatosHistoricosは、指定された資産の指定された日付範囲内の履歴データを取得します。CopyRates関数を利用してデータを取得し、MqlRates構造体の配列に格納します。この関数は、取得したデータを出力配列にコピーし、正しい形式とサイズが確保されるようにします。データの取得に失敗した場合にはエラーメッセージが表示され、成功した場合には、コピーされたデータ数を示す確認メッセージが表示されます。
calcularRendimientos関数は、履歴データを基に日々のリターンを計算します。データポイントを反復処理し、連続する日の終値の変化率としてリターンを計算します。この関数では、終値がゼロの場合などの潜在的なエラーを処理し、あらかじめ定義された閾値を超える異常なリターンをログに記録します。また、計算中に発生するリターンの最大値と最小値を追跡し、リターン計算を検証するために進捗状況を定期的に出力します。
メイン関数のOnStartは、履歴データを保存するための配列を初期化して返します。各資産銘柄を反復処理して、obtenerDatosHistoricosを呼び出してデータを取得し、その後にcalcularRendimientosを呼び出してリターンを計算します。リターン計算が完了した後、期待リターンと分散の計算に移ります。計算されたリターンを合計し、平均リターンを算出した後、リターンの分散を計算します。最終的に、期待リターン、分散、リターンの合計、有効なリターンの数などの結果が各資産ごとにコンソールに出力されます。データが不足している場合や形式が正しくない場合には、適切なメッセージがログ記録されます。
スクリプト全体にわたって透明性とデバッグの容易さを確保するために、広範なロギングが実装されています。データ取得、リターン計算、統計分析の進捗と結果がメッセージとして表示され、ユーザーは実行フローを追跡し、問題が発生した際に特定することができます。
このスクリプトを実行するには、スクリプトをウィンドウに読み込むだけです。
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 259 bars
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 259 data points for EURUSD
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Data size for EURUSD: 1554
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Calculating returns for 259 data points
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 49: 0.008422556659553942
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 99: 0.0005552522233225886
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 149: -0.0016251305097825213
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 199: -0.0018138190337636214
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 249: 0.002726296367691935
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 257: -0.0023503674709141444
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Max return: 0.016843640170492922, Min return: -0.014629419109562279
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Returns size for EURUSD: 258
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Results for EURUSD
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Expected return: 0.00014629557982735741
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Variance: 0.000021906221916670055
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Sum of returns: 0.03774425959545821
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Valid returns: 258 out of 258
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) -----------------------
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 259 bars
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 259 data points for GBPUSD
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Data size for GBPUSD: 1554
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Calculating returns for 259 data points
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 49: 0.01253428642673093
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 99: -0.00020901161622245828
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 149: -0.0009419054513750523
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 199: 0.00011442115156718484
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 249: -0.0024846582214581455
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 257: 0.000015710672259594492
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Max return: 0.01795095252445456, Min return: -0.016589470883191758
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Returns size for GBPUSD: 258
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Results for GBPUSD
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Expected return: 0.0002283507472210021
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Variance: 0.000026680765574142948
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Sum of returns: 0.058914492783018545
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Valid returns: 258 out of 258
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) -----------------------
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 250 bars
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 250 data points for #AAPL
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Data size for #AAPL: 1500
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Calculating returns for 250 data points
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 49: 0.026341719766143464
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 99: 0.010473614547965662
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 149: -0.006613315549627641
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 199: -0.0011390170283046702
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 248: -0.006298074441174946
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Max return: 0.047845736667670974, Min return: -0.04621826746924895
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Returns size for #AAPL: 249
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Results for #AAPL
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Expected return: 0.0018199882676706617
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Variance: 0.00016500191971009266
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Sum of returns: 0.4531770786499948
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Valid returns: 249 out of 249
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) -----------------------
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 250 bars
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Copied 250 data points for #AMZN
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Data size for #AMZN: 1500
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Calculating returns for 250 data points
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 49: 0.04365079365079357
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 99: 0.04105902777777781
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 149: -0.00952790314492451
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 199: -0.0033604251328539594
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Return for index 248: -0.009568443663346995
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Max return: 0.08595143898844165, Min return: -0.07525053686471019
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Returns size for #AMZN: 249
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Results for #AMZN
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Expected return: 0.002502188742255484
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Variance: 0.0004212375364322232
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Sum of returns: 0.6230449968216155
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) Valid returns: 249 out of 249
2024.07.11 21:46:42.458 optimizacion_carteras_v2 english (#AMZN,W1) -----------------------
結果からわかるように、AAPLには約40%、AMZNには約60%、EURUSDには約3%、GBPUSDには約6%の投資をおこなうべきです。これらの値は参考値であり、戦略は使われていません。
MQL5スクリプトへの戦略の追加
以下を最初のスクリプトに追加しなければなりません。
移動平均計算関数
この関数は、指定されたデータセットの指定された期間の移動平均を計算します。データポイントを反復処理し、定義された期間の終値を合計し、期間で割って平均を求めます。移動平均を計算するのに十分なデータがない場合、値はゼロに設定されます。
//+------------------------------------------------------------------+
//| Function to calculate moving average |
//+------------------------------------------------------------------+
void calcularMediaMovil(double &data[][6], int period, double &ma[])
{
int total = ArrayRange(data, 0);
ArrayResize(ma, total);
for(int i = 0; i < total; i++)
{
if(i >= period - 1)
{
double sum = 0;
for(int j = i; j > i - period; j--)
{
sum += data[j][4]; // Closing price
}
ma[i] = sum / period;
}
else
{
ma[i] = 0.0; // Not enough data for moving average
}
}
}
//+------------------------------------------------------------------+
//| Function to generate trading signals based on moving average cross |
//+------------------------------------------------------------------+
void generarSenales(double &data[][6], double &ma_rapida[], double &ma_lenta[], double &senales[])
{
int total = ArrayRange(data, 0);
ArrayResize(senales, total);
for(int i = 1; i < total; i++)
{
if(ma_rapida[i - 1] <= ma_lenta[i - 1] && ma_rapida[i] > ma_lenta[i])
{
senales[i] = 1; // Buy signal
}
else if(ma_rapida[i - 1] >= ma_lenta[i - 1] && ma_rapida[i] < ma_lenta[i])
{
senales[i] = -1; // Sell signal
}
else
{
senales[i] = 0; // No signal
}
}
}
これをOnStartに統合します。
void OnStart() { double data[][6]; double returns[]; for(int i = 0; i < ArraySize(symbols); i++) { obtenerDatosHistoricos(symbols[i], from_date, to_date, data); int data_size = ArraySize(data); if(data_size > 1 && ArrayRange(data, 1) == 6) { calcularRendimientos(data, returns); int returns_size = ArraySize(returns); double sum_returns = 0; int valid_returns = 0; for(int j = 0; j < returns_size; j++) { if(MathIsValidNumber(returns[j]) && MathAbs(returns[j]) <= 1.0) { sum_returns += returns[j]; valid_returns++; } } double mean_return = (valid_returns > 0) ? sum_returns / valid_returns : 0; double variance = 0; for(int j = 0; j < valid_returns; j++) { if(MathIsValidNumber(returns[j]) && MathAbs(returns[j]) <= 1.0) { variance += MathPow(returns[j] - mean_return, 2); } } variance = (valid_returns > 0) ? variance / valid_returns : 0; Print("Results for ", symbols[i]); Print("Expected return: ", mean_return); Print("Variance: ", variance); Print("Sum of returns: ", sum_returns); Print("Valid returns: ", valid_returns, " out of ", returns_size); Print("-----------------------"); // Calculate moving averages and trading signals double ma_rapida[]; double ma_lenta[]; double senales[]; int periodo_rapido = 10; // Short period moving average int periodo_lento = 50; // Long period moving average calcularMediaMovil(data, periodo_rapido, ma_rapida); calcularMediaMovil(data, periodo_lento, ma_lenta); generarSenales(data, ma_rapida, ma_lenta, senales); // Log trading signals for(int k = 0; k < ArraySize(senales); k++) { if(senales[k] != 0) { string tipo_senal = (senales[k] == 1) ? "Compra" : "Venta"; Print("Signal for ", symbols[i], " on ", TimeToString((datetime)data[k][0]), ": ", tipo_senal); } } } else { Print("Could not obtain enough data for ", symbols[i], " or the data format is incorrect"); Print("-----------------------"); } } }
この関数は、2本の移動平均線(短期間と長期間)のクロスに基づいて売買シグナルを生成します。短期間移動平均が長期間移動平均を上回ったり、下回ったりしていないか、データを反復処理して確認します。上にクロスすれば買いシグナル、下にクロスすれば売りシグナルとなります。クロスオーバーがなければ、シグナルは生成されません。
メイン関数OnStartへの統合
メイン関数では、各銘柄の履歴データを取得し、リターンを計算します。その後、各銘柄について移動平均と売買シグナルが計算されます。移動平均は、短い期間と長い期間の両方についてcalcularMediaMovil関数を使用して取得されます。generarSenales関数は、移動平均のクロスオーバーに基づいて売買シグナルを生成するために使用されます。計算されたシグナルを含む結果は、確認用にコンソールに出力されます。
このコードには、売買シグナルを生成する単純な移動平均クロスオーバー戦略が含まれています。取引シグナルはコンソールに表示され、必要に応じて移動平均の期間を調整できます。これが結果です。
2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 259 bars 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 259 data points for EURUSD 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Calculating returns for 259 data points 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 49: 0.008422556659553942 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 99: 0.0005552522233225886 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 149: -0.0016251305097825213 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 199: -0.0018138190337636214 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 249: 0.002726296367691935 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 257: -0.0023503674709141444 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Max return: 0.016843640170492922, Min return: -0.014629419109562279 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Results for EURUSD 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Expected return: 0.00014629557982735741 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Variance: 0.000021906221916670055 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Sum of returns: 0.03774425959545821 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Valid returns: 258 out of 258 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) ----------------------- 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.01.13 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.03.10 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.03.27 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.05.19 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.06.22 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.08.14 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for EURUSD on 2023.11.08 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 259 bars 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 259 data points for GBPUSD 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Calculating returns for 259 data points 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 49: 0.01253428642673093 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 99: -0.00020901161622245828 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 149: -0.0009419054513750523 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 199: 0.00011442115156718484 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 249: -0.0024846582214581455 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 257: 0.000015710672259594492 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Max return: 0.01795095252445456, Min return: -0.016589470883191758 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Results for GBPUSD 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Expected return: 0.0002283507472210021 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Variance: 0.000026680765574142948 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Sum of returns: 0.058914492783018545 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Valid returns: 258 out of 258 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) ----------------------- 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.01.13 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.03.10 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.03.23 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.05.26 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.06.12 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.08.10 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for GBPUSD on 2023.11.14 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 250 bars 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 250 data points for #AAPL 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Calculating returns for 250 data points 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 49: 0.026341719766143464 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 99: 0.010473614547965662 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 149: -0.006613315549627641 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 199: -0.0011390170283046702 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 248: -0.006298074441174946 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Max return: 0.047845736667670974, Min return: -0.04621826746924895 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Results for #AAPL 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Expected return: 0.0018199882676706617 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Variance: 0.00016500191971009266 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Sum of returns: 0.4531770786499948 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Valid returns: 249 out of 249 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) ----------------------- 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AAPL on 2023.01.17 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AAPL on 2023.08.10 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AAPL on 2023.10.18 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AAPL on 2023.10.20 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AAPL on 2023.11.10 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 250 bars 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Copied 250 data points for #AMZN 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Calculating returns for 250 data points 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 49: 0.04365079365079357 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 99: 0.04105902777777781 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 149: -0.00952790314492451 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 199: -0.0033604251328539594 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Return for index 248: -0.009568443663346995 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Max return: 0.08595143898844165, Min return: -0.07525053686471019 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Results for #AMZN 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Expected return: 0.002502188742255484 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Variance: 0.0004212375364322232 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Sum of returns: 0.6230449968216155 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Valid returns: 249 out of 249 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) ----------------------- 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AMZN on 2023.01.17 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AMZN on 2023.03.15 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AMZN on 2023.03.24 00:00: Compra 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AMZN on 2023.09.27 00:00: Venta 2024.07.11 22:02:03.328 optimizacion_carteras_v3 english (#AMZN,W1) Signal for #AMZN on 2023.11.07 00:00: Compra
この記事では、PythonとMQL5という2つのプログラミング言語とMetaTrader 5プラットフォームを活用して、ポートフォリオ最適化手法を深く掘り下げ、現代の金融管理におけるデータ駆動型の意思決定の重要性を明らかにします。過去のデータを分析し、資産配分を最適化するための高度なアルゴリズムを開発し、移動平均クロスオーバーに基づく売買シグナルの生成プロセスを詳細に解説します。
著者は、複雑化し変動が激しい投資環境において、リスク調整後リターンの最適化におけるポートフォリオ最適化の重要性を強調しています。高度な数学モデルと計算能力を駆使することで、これらのプログラムは、投資家がリスク許容度や投資目的に応じた情報に基づいた意思決定をおこなうための強力なツールとなります。この記事では、最適化技術が膨大な過去データを用いて市場動向や資産相関を体系的に分析し、ポートフォリオ全体のリスクを最小限に抑えながら潜在的リターンを最大化する方法を示しています。
戦略の初期テストにはPythonを使用し、MetaTrader 5とのシームレスな統合にはMQL5を活用するという2つのアプローチは、異なるプログラミング環境を組み合わせることで得られる多様性とパワーを示しています。この方法により、トレーダーはMetaTrader 5のネイティブ機能を利用しつつ、Pythonの豊富なライブラリと分析機能を最大限に活用することができます。
ポートフォリオ最適化を取引に取り入れることの重要性は、従来の投資戦略に見られる人間のバイアスや感情的な意思決定を減少させる科学的アプローチの提供にあります。グローバル経済の相互接続と情報の迅速な流れの時代において、これらの洗練されたツールは、投資家が不確実性を乗り越え、多様な資産クラスの機会を最大限に活用するための競争力を提供します。
この記事では、PythonとMQL5を用いた実装プロセスの詳細なウォークスルーを提供し、過去データの取得方法、リターンの計算方法、移動平均クロスオーバーに基づく売買シグナルの生成、そして資産配分の最適化方法について説明します。
要約すると、この記事は、高度なポートフォリオ最適化技術を通じて投資戦略を強化したいトレーダーや金融専門家にとって、貴重なリソースとなるでしょう。クオンツファイナンスとテクノロジーの相乗効果に焦点を当て、堅牢で適応性の高い取引システムの開発に関する実践的な洞察を提供します。著者は、今日のダイナミックな金融市場において、効率的なリスク調整後リターンを達成し、弾力的な投資戦略を構築するために、こうしたツールが不可欠であると結論付けています。
結論
結論として、PythonとMQL5の統合によるポートフォリオ最適化は、Pythonの高度な分析能力とMetaTrader 5の取引機能を組み合わせることで、取引戦略の開発における重要な進歩をもたらします。これらの先進的なプログラムは、トレーダーが過去のデータを分析し、資産配分を最適化し、その結果を効果的に視覚化できるよう設計されており、金融市場におけるデータ駆動型意思決定の強化に寄与します。
Pythonの広範なライブラリ(Pandas、NumPy、cvxpyなど)とMetaTrader 5のネイティブMQL5スクリプトを活用することで、トレーダーはポートフォリオ管理の効率を向上させ、市場の変動に柔軟に対応することができます。この二重のアプローチにより、Pythonでのストラテジー初期テストの簡便さと、MetaTrader 5環境での実用的な適用性および精度が保証されます。金融環境がますます複雑化し、変動が激しくなる現代において、これらの洗練されたツールは、効率的なリスク調整後リターンの達成において不可欠です。高度な数学モデルを駆使し、人間のバイアスを排除することで、これらのポートフォリオ最適化プログラムは、レジリエントで堅固な投資戦略を構築するための強力なフレームワークを提供します。
本記事にご関心をお寄せいただきありがとうございます。取引パフォーマンスの向上と戦略的な財務管理のために、ぜひこれらのツールをさらにご検討ください。ありがとうございました。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/15288





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索