192 lines
8.2 KiB
MQL5
192 lines
8.2 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CorrelationMatrix.mq5 |
|
||
|
|
//| 多品种相关性分析矩阵 v1.0 |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "Copyright 2026"
|
||
|
|
#property version "1.00"
|
||
|
|
#property script_show_inputs
|
||
|
|
|
||
|
|
// --- 输入参数(可自行调整)---
|
||
|
|
input int iBars_P = 30; // 使用的K线数量
|
||
|
|
input ENUM_TIMEFRAMES iTimeframe = PERIOD_H4; // 时间周期(日线/4H/1H)
|
||
|
|
string Symbols[4] = {"XAUUSDm","EURUSDm","GBPUSDm","GBPJPYm"};
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| 脚本主入口 |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnStart()
|
||
|
|
{
|
||
|
|
// --- 1. 获取原始价格数据(收盘价)---
|
||
|
|
Print("========== 开始计算多品种相关性矩阵 ==========");
|
||
|
|
Print("品种列表:", Symbols[0], ", ", Symbols[1], ", ", Symbols[2], ", ", Symbols[3]);
|
||
|
|
Print("K线数量:", iBars_P, " 根,周期:", EnumToString(iTimeframe));
|
||
|
|
|
||
|
|
int nSymbols = 4; // 四个品种
|
||
|
|
double close_prices[];
|
||
|
|
ArrayResize(close_prices, iBars_P);
|
||
|
|
|
||
|
|
// 创建矩阵:iBars行 × nSymbols列(每列存储一个品种的收盘价)
|
||
|
|
matrix priceMatrix(iBars_P, nSymbols);
|
||
|
|
SymbolSelect(Symbols[0],true);
|
||
|
|
SymbolSelect(Symbols[1],true);
|
||
|
|
SymbolSelect(Symbols[2],true);
|
||
|
|
SymbolSelect(Symbols[3],true);
|
||
|
|
// 为每个品种获取历史收盘价
|
||
|
|
for(int s = 0; s < nSymbols; s++)
|
||
|
|
{
|
||
|
|
// 调用CopyRates将收盘价直接复制到向量(使用Mql5矩阵方法)
|
||
|
|
vector close_vector; // 创建一个向量来存储收盘价
|
||
|
|
|
||
|
|
// 从历史中复制iBars根K线的收盘价
|
||
|
|
// COPY_RATES_CLOSE 是一个标志,表示只复制收盘价
|
||
|
|
// 参数:品种名称,时间周期,要复制的内容,起始索引,数量
|
||
|
|
// SymbolSelect(Symbols[s],true);
|
||
|
|
bool success = close_vector.CopyRates(Symbols[s], iTimeframe, COPY_RATES_CLOSE, 0, iBars_P);
|
||
|
|
|
||
|
|
if(!success)
|
||
|
|
{
|
||
|
|
Print("错误:无法获取 ", Symbols[s], " 的历史数据!");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 将收盘价向量赋值到矩阵的列中
|
||
|
|
for(int i = 0; i < iBars_P; i++)
|
||
|
|
{
|
||
|
|
priceMatrix[i][s] = close_vector[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
Print(Symbols[s], " 数据已获取,大小:", close_vector.Size());
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- 2. 计算对数收益率矩阵 ---
|
||
|
|
// 对数收益率公式:r = ln(P_t / P_{t-1})
|
||
|
|
// 这将创建(iBars_P-1)行的收益率矩阵
|
||
|
|
matrix retMatrix(iBars_P-1, nSymbols);
|
||
|
|
|
||
|
|
for(int s = 0; s < nSymbols; s++)
|
||
|
|
{
|
||
|
|
for(int i = 0; i < iBars_P-1; i++)
|
||
|
|
{
|
||
|
|
// 收盘价严格大于0
|
||
|
|
if(priceMatrix[i+1][s] > 0 && priceMatrix[i][s] > 0)
|
||
|
|
{
|
||
|
|
retMatrix[i][s] = MathLog(priceMatrix[i+1][s] / priceMatrix[i][s]);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
retMatrix[i][s] = 0.0; // 如果数据无效,设为0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Print("对数收益率矩阵已创建,大小:", retMatrix.Rows(), " 行 × ", retMatrix.Cols(), " 列");
|
||
|
|
|
||
|
|
// --- 3. 计算相关性矩阵 ---
|
||
|
|
// 使用矩阵的CorrCoef方法:计算各行(观察值)之间的相关系数
|
||
|
|
// 参数:true表示按行计算(每一行是一个观察点,每一列是一个变量)
|
||
|
|
// 由于我们的矩阵布局是:行=时间,列=品种,所以应该使用 rowvar=true
|
||
|
|
matrix corrMatrix = retMatrix.CorrCoef(true); // 这会生成一个 4x4 的对称矩阵
|
||
|
|
|
||
|
|
// --- 4. 输出相关性矩阵结果 ---
|
||
|
|
Print("\n===== 相关性矩阵(Pearson相关系数) =====");
|
||
|
|
Print("矩阵对角线都是1.0(每个品种与自身的相关性)");
|
||
|
|
Print("矩阵对称,右上角和左下角的值相同");
|
||
|
|
Print("");
|
||
|
|
|
||
|
|
// 设置打印格式,精确到小数点后4位
|
||
|
|
string header = " ";
|
||
|
|
for(int s = 0; s < nSymbols; s++)
|
||
|
|
header += StringFormat("%10s", Symbols[s]);
|
||
|
|
Print(header);
|
||
|
|
|
||
|
|
for(int i = 0; i < nSymbols; i++)
|
||
|
|
{
|
||
|
|
string row = StringFormat("%10s", Symbols[i]);
|
||
|
|
for(int j = 0; j < nSymbols; j++)
|
||
|
|
{
|
||
|
|
double corr = corrMatrix[i][j];
|
||
|
|
string corrStr;
|
||
|
|
if(MathAbs(corr) >= 0.7)
|
||
|
|
corrStr = StringFormat("%10.2f*", corr); // 强相关用*标记
|
||
|
|
else if(MathAbs(corr) >= 0.3)
|
||
|
|
corrStr = StringFormat("%10.2f", corr);
|
||
|
|
else
|
||
|
|
corrStr = StringFormat("%10.2f", corr);
|
||
|
|
row += corrStr;
|
||
|
|
}
|
||
|
|
Print(row);
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- 5. 详细解读两两相关性 ---
|
||
|
|
Print("\n===== 两两相关性详细解读 =====");
|
||
|
|
for(int i = 0; i < nSymbols; i++)
|
||
|
|
{
|
||
|
|
for(int j = i+1; j < nSymbols; j++)
|
||
|
|
{
|
||
|
|
double corr = corrMatrix[i][j];
|
||
|
|
string relationship;
|
||
|
|
|
||
|
|
if(corr >= 0.7)
|
||
|
|
relationship = "强正相关(通常同涨同跌)";
|
||
|
|
else if(corr >= 0.3)
|
||
|
|
relationship = "弱正相关(有一定同向性)";
|
||
|
|
else if(corr > -0.3)
|
||
|
|
relationship = "无明显相关性(可分散风险)";
|
||
|
|
else if(corr > -0.7)
|
||
|
|
relationship = "弱负相关(有一定反向性)";
|
||
|
|
else
|
||
|
|
relationship = "强负相关(反向对冲)";
|
||
|
|
|
||
|
|
PrintFormat("%s 与 %s:相关性 = %.4f (%s)",
|
||
|
|
Symbols[i], Symbols[j], corr, relationship);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- 6. 基于相关性的实用建议 ---
|
||
|
|
Print("\n===== 基于相关性的组合风险提示 =====");
|
||
|
|
|
||
|
|
// 检查EURUSD与GBPUSD的相关性(同受美元影响)
|
||
|
|
double usd_pair_corr = corrMatrix[1][2]; // EURUSD vs GBPUSD
|
||
|
|
PrintFormat("⚠️ EURUSD与GBPUSD相关性:%.4f", usd_pair_corr);
|
||
|
|
if(usd_pair_corr > 0.7)
|
||
|
|
Print(" → 同时持有这两个货币对的多头仓位,实际上是把对美元的赌注翻倍了!");
|
||
|
|
else if(usd_pair_corr > 0.5)
|
||
|
|
Print(" → 这两个货币对走势高度相关,同时开单会放大风险敞口,建议只选一个。");
|
||
|
|
|
||
|
|
// 检查黄金与美元货币对的关系(黄金通常与美元负相关)
|
||
|
|
double gold_eur_corr = corrMatrix[0][1]; // XAUUSD vs EURUSD
|
||
|
|
PrintFormat("💰 XAUUSD与EURUSD相关性:%.4f", gold_eur_corr);
|
||
|
|
if(gold_eur_corr < -0.3)
|
||
|
|
Print(" → 黄金与欧元兑美元呈负相关,可作为组合中的分散化工具。");
|
||
|
|
else if(gold_eur_corr > 0.3)
|
||
|
|
Print(" → 黄金与欧元走势同向,可能在美元波动时产生叠加效应。");
|
||
|
|
|
||
|
|
// 检查GBPJPY的独立性(日元避险属性)
|
||
|
|
double gbpjpy_eur_corr = corrMatrix[3][1]; // GBPJPY vs EURUSD
|
||
|
|
double gbpjpy_gold_corr = corrMatrix[3][0]; // GBPJPY vs XAUUSD
|
||
|
|
PrintFormat("🇬🇧🇯🇵 GBPJPY与EURUSD相关性:%.4f", gbpjpy_eur_corr);
|
||
|
|
PrintFormat("🇬🇧🇯🇵 GBPJPY与XAUUSD相关性:%.4f", gbpjpy_gold_corr);
|
||
|
|
if(MathAbs(gbpjpy_eur_corr) < 0.3 && MathAbs(gbpjpy_gold_corr) < 0.3)
|
||
|
|
Print(" → GBPJPY与其他品种相关性较低,是很好的组合分散化选择。");
|
||
|
|
|
||
|
|
Print("\n========== 相关性分析完成 ==========");
|
||
|
|
}
|
||
|
|
|
||
|
|
// 辅助函数:将周期枚举转换为字符串
|
||
|
|
string EnumToString(ENUM_TIMEFRAMES tf)
|
||
|
|
{
|
||
|
|
switch(tf)
|
||
|
|
{
|
||
|
|
case PERIOD_M1: return "M1";
|
||
|
|
case PERIOD_M5: return "M5";
|
||
|
|
case PERIOD_M15: return "M15";
|
||
|
|
case PERIOD_M30: return "M30";
|
||
|
|
case PERIOD_H1: return "H1";
|
||
|
|
case PERIOD_H4: return "H4";
|
||
|
|
case PERIOD_D1: return "D1";
|
||
|
|
case PERIOD_W1: return "W1";
|
||
|
|
case PERIOD_MN1: return "MN1";
|
||
|
|
default: return "Unknown";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|