English Русский Español Deutsch 日本語
preview
基于Python与MQL5的特征工程(第三部分):价格角度(2)——极坐标(Polar Coordinates)法

基于Python与MQL5的特征工程(第三部分):价格角度(2)——极坐标(Polar Coordinates)法

MetaTrader 5示例 |
200 4
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

将价格变化转化为角度变化的探索热情未减。正如本系列前文所述,要成功将价格水平变化转化为能代表该变化的角度值,仍需克服诸多挑战。

在社区论坛和帖子中,最常被提及的局限性之一是:此类计算背后缺乏可解释的实际意义。经验丰富的社区成员往往会指出:角度存在于两条直线之间,因此试图通过价格变化计算角度在现实世界中并无实际意义。 

对于希望计算价格变化所形成角度的交易者而言,缺乏现实世界中的可解释性仅是众多待克服的挑战之一。在前文中,我们曾尝试通过替换X轴的时间变量,使生成的角度成为价格水平的比率,从而赋予其一定的解释意义。然而在探索过程中,我们发现经此转换后的数据集极易出现大量“无穷大”值。欲快速回顾前文观察结果的读者,可点击此处查阅相关文章。

在尝试将价格变化转化为对应角度变化时,由于缺乏明确的现实世界意义,相关领域的系统性资料极为有限。 

我们将从全新的角度解决价格到角度的转换问题。本次,我们将采用比首次尝试时更数学严谨且稳健的方法攻克这一难题。熟悉极坐标的读者可直接跳转至“MQL5实战入门”章节,查看这些数学工具在MQL5中的实现方式。 

否则,我们将从基础概念入手,理解极坐标的本质,并建立直观认知:将其应用于MetaTrader 5终端中,计算由价格变化形成的角度,并将这些信号转化为交易策略。也就是说:

  1. 我们的解决方案具有现实意义。
  2. 我们也同时解决此前无限值或未定义值的问题。


极坐标的定义与应用价值

当我们使用GPS技术或简单的电子表格时,实际上依赖的是笛卡尔坐标系(Cartesian Coordinates)。这是一种通过两组垂直轴表示平面内点的数学系统。 

在笛卡尔坐标系中,任意一点由(x, y)坐标对表示:x代表该点与原点的水平距离,y代表该点与原点的垂直距离。 

如果需研究具有周期性成分或圆周运动的过程,极坐标比笛卡尔坐标系更适用。极坐标通过两个参数表示平面内点:与参考点(原点)的径向距离和与参考方向的夹角(逆时针方向为正)  

金融市场常表现出近乎周期性的重复模式。因此极坐标可能成为其理想表示方式。通过将价格水平表示为极坐标对(r, θ),可以自然得出交易者所需计算的价格变化角度。 

极坐标以(r, θ)对表示,其中:

  • r:表示径向距离(与原点的距离)
  • θ:表示参考方向测量的角度

借助MQL5矩阵与向量API的三角函数,可无缝将价格变化转换为表示价格变动的角度。 

为实现目标,我们需要先熟悉在讨论中会使用的术语。首先,我们必须定义将被转换的x和y输入。在讨论中,我们将x设置为交易品种的开盘价,y设置为收盘价。

截图1

图例1:定义待转换为极坐标的笛卡尔坐标点

在定义好x轴(开盘价)与y轴(收盘价)的输入值后,下一步我们需要计算极坐标对(r, θ)中的首个元素——径向距离r(即该点与原点的距离)。 

截图2

图例2:基于笛卡尔坐标(x, y)计算径向距离r的闭合公式

从几何角度理解,极坐标可视为对圆的描述。径向距离r与x轴形成的夹角即为θ。因此,极坐标通过r与θ的组合,能够等效传递与笛卡尔坐标(x, y)相同的信息。如图例3所示,当x与y在坐标系中呈现为直角三角形的两条直角边时,可通过x边与y边应用勾股定理计算径向距离r。

截图3

图例3:极坐标可视为对圆上点的描述

径向距离r与x轴的夹角θ,赋予了极坐标实际的分析价值。在此简单示例中,θ反映了开盘价与收盘价变动所形成趋势的方向。如下图所示,θ可通过计算收盘价与开盘价的反正切值得出:

截图4

图例4:基于开盘价(x)与收盘价(y)计算角度θ

给定任意极坐标(r, θ),可通过以下两个公式轻松还原其原始价格水平:

截图5

图例5:极坐标转换为笛卡尔坐标的方法

截至目前,我们讨论了4个公式,但仅后3个公式涉及角度θ。第一个计算r的公式与θ无关。后3个公式均包含θ,并且可以明确区分。这些三角函数的导数均为大众熟知的结果,可在任意基础微积分教材或在线资源中查询。 

我们将利用这3个导数作为附加的输入,训练计算机学习角度变化与价格水平变化的关联性。


MQL5入门指南

让我们开始吧。我们首先需要编写一个MQL5脚本,从MetaTrader 5终端获取历史市场数据,并计算生成的角度值。

我们需要定义所创建CSV文件名,并指定要获取的K线数量。由于不同经纪商可供获取的历史K线数量可能不同,因此该参数已设为脚本的外部输入项。

#property copyright "Gamuchirai Zororo Ndawana"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs

//---File name
string file_name = _Symbol + " " + " Polar Coordinates.csv";

//---Amount of data requested
input int size = 100;
int size_fetch = size + 100;

当执行脚本时,我们将创建一个文件句柄,用于把价格水平及其对应的角度变化写入文件。

void OnStart()
  {
      //---Write to file
       int file_handle=FileOpen(file_name,FILE_WRITE|FILE_ANSI|FILE_CSV,",");
       
    for(int i=size;i>0;i--){
      if(i == size){
            FileWrite(file_handle,"Time","Open","High","Low","Close","R","Theta","X Derivatie","Y Derivative","Theta Derivative");
      }
      
      else{

接下来,我们使用图例2中讨论的公式计算r。

double r = MathSqrt(MathPow(iOpen(_Symbol,PERIOD_CURRENT,i),2) + MathPow(iClose(_Symbol,PERIOD_CURRENT,i),2));

θ通过y与x比值的反正切计算得出。MQL5 API已为我们提供了相应函数。

double theta = MathArctan2(iClose(_Symbol,PERIOD_CURRENT,i),iOpen(_Symbol,PERIOD_CURRENT,i));

回顾上面图例5所给出的计算x(开盘价)的公式。我们可对该式关于θ求导,得到开盘价的一阶导数。如您所知,cos( )的导数为-sin( )。

double derivative_x = r * (-(MathSin(theta)));

同样地,由于我们已经掌握三角函数的导数,因此也可以求出y的导数。

double derivative_y = r * MathCos(theta);

最后,我们已知角度θ的一阶导数。然而,MQL5 API并未直接提供三角函数运算,因此需通过数学恒等式将其替换为MQL5内置函数可处理的形式。

double derivative_theta = (1/MathPow(MathCos(theta),2));

既然已计算出角度值,我们即可着手将数据写入输出文件。

           FileWrite(file_handle,iTime(_Symbol,PERIOD_CURRENT,i),
                                 iOpen(_Symbol,PERIOD_CURRENT,i),
                                 iHigh(_Symbol,PERIOD_CURRENT,i),
                                 iLow(_Symbol,PERIOD_CURRENT,i),
                                 iClose(_Symbol,PERIOD_CURRENT,i),
                                 r,
                                 theta,
                                 derivative_x,
                                 derivative_y,
                                 derivative_y
                                 );
      } 
    }
    
    FileClose(file_handle);
  }
//+---------


数据分析

既然数据已经以CSV格式导出,我们即可利用其训练计算机识别交易形成的角度。为加速开发进程,我们将调用多个Python库实现功能。

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

对数据进行标注,记录次日价格水平是上涨还是下跌。

data = pd.read_csv("EURUSD  Polar Coordinates.csv")
data["UP DOWN"] = 0
data.loc[data["Close"] < data["Close"].shift(-1),"UP DOWN"] = 1
data

以下是我们寻找的交易信号。请注意,当原始数据集中的r与θ同时增大时,价格水平从未下跌。调用该pandas未返回任何结果,这恰好印证了极坐标对在现实交易中的实际意义。掌握r与θ的未来值,等同于预知未来价格水平。

data.loc[(data["R"] < data["R"].shift(-1)) & (data['Theta'] < data['Theta'].shift(-1)) & (data['Close'] > data['Close'].shift(-1))

同理,若我们执行相同的查询但方向相反——即寻找r与θ均增大,但未来价格下跌的实例——则会发现pandas仍返回0条匹配结果。

data.loc[(data["R"] > data["R"].shift(-1)) & (data['Theta'] > data['Theta'].shift(-1)) & (data['Close'] < data['Close'].shift(-1))]

因此,当计算机预测r与θ的未来值将大于当前值时,即可生成交易信号。接下来,我们可将价格数据以极坐标圆上的点进行可视化。如图例6所示,数据仍难以实现有效地分离。

data['Theta_rescaled'] = (data['Theta'] - data['Theta'].min()) / (data['Theta'].max() - data['Theta'].min()) * (2 * np.pi)
data['R_rescaled'] = (data['R'] - data['R'].min()) / (data['R'].max() - data['R'].min()) 

# Create the polar plot
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'})

# Plot data points on the polar axis
ax.scatter(data['Theta_rescaled'], data['R_rescaled'],c=data["UP DOWN"], cmap='viridis', edgecolor='black', s=100)

# Add plot labels
ax.set_title("Polar Plot of OHLC Points")
plt.colorbar(plt.cm.ScalarMappable(cmap='viridis'), ax=ax, label='1(UP) | O(DOWN)')

plt.show()

截图6

图例6:以极坐标圆上的极点形式可视化价格数据

让我们快速核查数据中是否存在空值。

data.isna().any()

截图7

图例7:检查所有值是否为空


数据建模

完美定义所有数据值。接下来,我们需要对数据进行标注。再次提醒,我们的预测目标是θ与r的未来值。

LOOK_AHEAD = 1
data['R Target'] = data['R'].shift(-LOOK_AHEAD)
data['Theta Target'] = data['Theta'].shift(-LOOK_AHEAD)
data.dropna(inplace=True)
data.reset_index(drop=True,inplace=True)

请记住,我们需剔除最后两年的数据,以便将其作为模型应用的测试集。

#Let's entirely drop off the last 2 years of data
_ = data.iloc[-((365 * 2) + 230):,:]
data = data.iloc[:-((365 * 2) + 230),:]
data

截图8

图例8:剔除最后两年数据后的数据集

当前,使用现有数据训练计算机模型。我们选择梯度提升树作为模型,因其特别擅长捕捉变量间的交互效应。

from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split,TimeSeriesSplit,cross_val_score

现定义时间序列分割对象。

tscv = TimeSeriesSplit(n_splits=5,gap=LOOK_AHEAD)

定义输入和目标。

X = data.columns[1:-5]
y = data.columns[-2:]

将数据分为训练和测试两部分。

train , test = train_test_split(data,test_size=0.5,shuffle=False)

现在划分训练集与测试集。

train_X = train.loc[:,X]
train_y = train.loc[:,y]

test_X = test.loc[:,X]
test_y = test.loc[:,y]

需要标准化训练和测试的划分。

mean_scores = train_X.mean()
std_scores = train_X.std()

缩放数据。

train_X = ((train_X - mean_scores) / std_scores)
test_X = ((test_X - mean_scores) / std_scores)

初始化模型。

model = GradientBoostingRegressor()

准备一张表格用于存储结果。

results = pd.DataFrame(index=["Train","Test"],columns=["GBR"])

调整模型以预测r。

results.iloc[0,0] = np.mean(np.abs(cross_val_score(model,train_X,train_y["R Target"],cv=tscv)))
results.iloc[1,0] = np.mean(np.abs(cross_val_score(model,test_X,test_y["R Target"],cv=tscv)))
results
GBR
训练 0.76686
测试   0.89129

调整模型以预测θ。

results.iloc[0,0] = np.mean(np.abs(cross_val_score(model,train_X,train_y["Theta Target"],cv=tscv)))
results.iloc[1,0] = np.mean(np.abs(cross_val_score(model,test_X,test_y["Theta Target"],cv=tscv)))
results
GBR
训练 0.368166
测试 0.110126


导出到ONNX

加载我们需要的库。

import onnx
import skl2onnx 
from skl2onnx.common.data_types import FloatTensorType

初始化两个模型。

r_model = GradientBoostingRegressor()
theta_model = GradientBoostingRegressor()

将全局标准化分数存储为CSV格式文件。

mean_scores = data.loc[:,X].mean()
std_scores = data.loc[:,X].std()

mean_scores.to_csv("EURUSD Polar Coordinates Mean.csv")
std_scores.to_csv("EURUSD Polar Coordinates Std.csv")

初始化整个数据集。

data[X] = ((data.loc[:,X] - mean_scores) / std_scores)

根据缩放的数据调整模型。

r_model.fit(data.loc[:,X],data.loc[:,'R Target'])
theta_model.fit(data.loc[:,X],data.loc[:,'Theta Target'])

定义输入形状。

initial_types = [("float_input",FloatTensorType([1,len(X)]))]

准备用于保存的ONNX原型。

r_model_proto = skl2onnx.convert_sklearn(r_model,initial_types=initial_types,target_opset=12)
theta_model_proto = skl2onnx.convert_sklearn(theta_model,initial_types=initial_types,target_opset=12)

保存ONNX文件。

onnx.save(r_model_proto,"EURUSD D1 R Model.onnx")
onnx.save(theta_model_proto,"EURUSD D1 Theta Model.onnx")


MQL5入门指南

现在,我们准备构建我们的交易应用程序。

//+------------------------------------------------------------------+
//|                                              EURUSD Polar EA.mq5 |
//|                                               Gamuchirai Ndawana |
//|                    https://www.mql5.com/en/users/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Ndawana"
#property link      "https://www.mql5.com/en/users/gamuchiraindawa"
#property version   "1.00"

//+------------------------------------------------------------------+
//| System Constants                                                 |
//+------------------------------------------------------------------+
#define ONNX_INPUTS 9                                              //The total number of inputs for our onnx model
#define ONNX_OUTPUTS 1                                             //The total number of outputs for our onnx model
#define TF_1  PERIOD_D1                                            //The system's primary time frame
#define TRADING_VOLUME 0.1                                         //The system's trading volume

作为系统资源加载ONNX模型。

//+------------------------------------------------------------------+
//| System Resources                                                 |
//+------------------------------------------------------------------+
#resource "\\Files\\EURUSD D1 R Model.onnx" as uchar r_model_buffer[];
#resource "\\Files\\EURUSD D1 Theta Model.onnx" as uchar theta_model_buffer[];

定义我们的全局变量。我们将使用其中一些变量标准化我们的数据,存储ONNX模型的预测等等。

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
double mean_values[] = {1.1884188643844635,1.1920754015799868,1.1847545720868993,1.1883860236998025,1.6806588395310122,0.7853854898794739,-1.1883860236998025,1.1884188643844635,1.1884188643844635};
double std_values[]  = {0.09123896995032886,0.09116171300874902,0.0912656190371797,0.09120265318308786,0.1289537623737421,0.0021932437785043796,0.09120265318308786,0.09123896995032886,0.09123896995032886};
double current_r,current_theta;
long r_model,theta_model;
vectorf r_model_output = vectorf::Zeros(ONNX_OUTPUTS);
vectorf theta_model_output = vectorf::Zeros(ONNX_OUTPUTS);
double bid,ask;
int ma_o_handler,ma_c_handler,state;
double ma_o_buffer[],ma_c_buffer[];

加载交易库。

//+------------------------------------------------------------------+
//| Library                                                          |
//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>
CTrade Trade;

我们的交易应用主要由事件处理器构成。在应用生命周期的每个阶段,我们将调用专用函数执行与当前目标对应的任务。因此,初始化阶段会设置技术指标,而当新价格数据到达时,则更新这些指标的读数。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!setup())
     {
      Comment("Failed To Load Corretly");
      return(INIT_FAILED);
     }

   Comment("Started");
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   OnnxRelease(r_model);
   OnnxRelease(theta_model);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   update();
  }
//+------------------------------------------------------------------+

从ONNX模型获取预测结果。请注意,我们将所有模型输入强制转换为浮点类型,以确保模型接收到符合其预期格式和大小的数据。

//+------------------------------------------------------------------+
//| Get a prediction from our models                                 |
//+------------------------------------------------------------------+
void get_model_prediction(void)
  {
//Define theta and r
   double o = iOpen(_Symbol,PERIOD_CURRENT,1);
   double h = iHigh(_Symbol,PERIOD_CURRENT,1);
   double l = iLow(_Symbol,PERIOD_CURRENT,1);
   double c = iClose(_Symbol,PERIOD_CURRENT,1);
   current_r = MathSqrt(MathPow(o,2) + MathPow(c,2));
   current_theta = MathArctan2(c,o);

   vectorf model_inputs =
     {
      (float) o,
      (float) h,
      (float) l,
      (float) c,
      (float) current_r,
      (float) current_theta,
      (float)(current_r * (-(MathSin(current_theta)))),
      (float)(current_r * MathCos(current_theta)),
      (float)(1/MathPow(MathCos(current_theta),2))
     };

//Standardize the model inputs
   for(int i = 0; i < ONNX_INPUTS;i++)
     {
      model_inputs[i] = (float)((model_inputs[i] - mean_values[i]) / std_values[i]);
     }

//Get a prediction from our model
   OnnxRun(r_model,ONNX_DATA_TYPE_FLOAT,model_inputs,r_model_output);
   OnnxRun(theta_model,ONNX_DATA_TYPE_FLOAT,model_inputs,theta_model_output);

//Give our prediction
   Comment(StringFormat("R: %f \nTheta: %f\nR Forecast: %f\nTheta Forecast: %f",current_r,current_theta,r_model_output[0],theta_model_output[0]));
  }

每当有新的价格出现时,请更新系统。

//+------------------------------------------------------------------+
//| Update system state                                              |
//+------------------------------------------------------------------+
void update(void)
  {
   static datetime time_stamp;
   datetime current_time = iTime(_Symbol,TF_1,0);

   bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
   ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   if(current_time != time_stamp)
     {
      CopyBuffer(ma_o_handler,0,0,1,ma_o_buffer);
      CopyBuffer(ma_c_handler,0,0,1,ma_c_buffer);
      time_stamp = current_time;
      get_model_prediction();
      manage_account();
      if(PositionsTotal() == 0)
         get_signal();
     }
  }

管理交易账户。如果某笔交易出现亏损,我们将立即平仓止损。否则,如果已进场但均线交叉形态动摇我们对持仓的信心,则立即平仓离场。

//+------------------------------------------------------------------+
//| Manage the open positions we have in the market                  |
//+------------------------------------------------------------------+
void manage_account()
  {
   if(AccountInfoDouble(ACCOUNT_BALANCE) < AccountInfoDouble(ACCOUNT_EQUITY))
     {
      while(PositionsTotal() > 0)
         Trade.PositionClose(Symbol());
     }

   if(state == 1)
     {
      if(ma_c_buffer[0] < ma_o_buffer[0])
         Trade.PositionClose(Symbol());
     }

   if(state == -1)
     {
      if(ma_c_buffer[0] > ma_o_buffer[0])
         Trade.PositionClose(Symbol());
     }
  }

设置系统变量,如技术指标和ONNX模型。

//+------------------------------------------------------------------+
//| Setup system variables                                           |
//+------------------------------------------------------------------+
bool setup(void)
  {
   ma_o_handler = iMA(Symbol(),TF_1,50,0,MODE_SMA,PRICE_CLOSE);
   ma_c_handler = iMA(Symbol(),TF_1,10,0,MODE_SMA,PRICE_CLOSE);

   r_model = OnnxCreateFromBuffer(r_model_buffer,ONNX_DEFAULT);
   theta_model = OnnxCreateFromBuffer(theta_model_buffer,ONNX_DEFAULT);

   if(r_model == INVALID_HANDLE)
      return(false);
   if(theta_model == INVALID_HANDLE)
      return(false);

   ulong input_shape[] = {1,ONNX_INPUTS};
   ulong output_shape[] = {1,ONNX_OUTPUTS};

   if(!OnnxSetInputShape(r_model,0,input_shape))
      return(false);
   if(!OnnxSetInputShape(theta_model,0,input_shape))
      return(false);

   if(!OnnxSetOutputShape(r_model,0,output_shape))
      return(false);
   if(!OnnxSetOutputShape(theta_model,0,output_shape))
      return(false);

   return(true);
  }

检查是否存在交易信号。我们主要核查均线交叉策略的指向性。随后,将验证ONNX模型给出的预期结果。因此,若均线交叉显示看跌信号,但r与θ两个ONNX模型给出看涨信号,则暂不进场,直至两套系统达成一致。

//+------------------------------------------------------------------+
//| Check if we have a trading signal                                |
//+------------------------------------------------------------------+
void get_signal(void)
  {
   if(ma_c_buffer[0] > ma_o_buffer[0])
     {
      if((r_model_output[0] < current_r) && (theta_model_output[0] < current_theta))
        {
         return;
        }
        
      if((r_model_output[0] > current_r) && (theta_model_output[0] > current_theta))
        {
         Trade.Buy(TRADING_VOLUME * 2,Symbol(),ask,0,0);
         Trade.Buy(TRADING_VOLUME * 2,Symbol(),ask,0,0);
         state = 1;
         return;
        }
        
      Trade.Buy(TRADING_VOLUME,Symbol(),ask,0,0);
      state = 1;
      return;
     }

   if(ma_c_buffer[0] < ma_o_buffer[0])
     {
      if((r_model_output[0] > current_r) && (theta_model_output[0] > current_theta))
        {
         return;
        }

     if((r_model_output[0] < current_r) && (theta_model_output[0] < current_theta))
        {
         
         Trade.Sell(TRADING_VOLUME * 2,Symbol(),bid,0,0);
         Trade.Sell(TRADING_VOLUME * 2,Symbol(),bid,0,0);
         state = -1;
         return;
        }

      Trade.Sell(TRADING_VOLUME,Symbol(),bid,0,0);
      state = -1;
      return;
     }
  }

我们没有使用未定义的系统常数。

//+------------------------------------------------------------------+
//| Undefine system variables we don't need                          |
//+------------------------------------------------------------------+
#undef ONNX_INPUTS
#undef ONNX_OUTPUTS
#undef TF_1
//+------------------------------------------------------------------+


系统测试

现在,让我们开始测试系统。再次提醒,在数据预处理阶段,我们删除了2022年1月1日的数据,以确保回测结果能真实反映策略在完全未见过的数据上的表现。

截图9

图例9:回测设置

现在指定初始帐户设置。 



图例10:针对样本外数据的第二轮关键回测参数配置

我们可以观察到新系统生成的交易信号净值曲线。策略初始资金为5000美元,最终资金约7000美元,收益良好,激励我们持续优化策略。

截图11

图例11:基于角度变换信号的回测结果

让我们对结果进行详细分析。该策略在样本外数据上的准确率达到88%。这一数据颇具鼓舞性,可为读者提供良好的起点——通过扩展我们在本应用中演示的MetaTrader 5终端功能,构建自有应用。或者可以将我们的框架作为参考,完全替换为读者自研的交易策略。

截图12

图例12:回测结果深度解析


结论

今日展示的解决方案,演示了如何通过将价格水平变化转化为角度变化,挖掘潜在交易优势。我们的方法为您提供了一个简洁优雅的框架,既融合交易逻辑又兼顾数学逻辑,实现二者的最优平衡。更重要的是,不同于盲目预测价格的普通市场参与者,您现在掌握了替代性预测目标——这些目标与价格本身同等重要,且比价格本身更易实现稳定地预测。

附件文件 描述
极坐标获取数据 为获取价格数据并将其转换为极坐标而定制的脚本。
欧元兑美元极坐标EA 基于角度变化生成信号交易的EA
欧元兑美元日线级(D1)r模型 负责预测r未来值的ONNX模型
欧元兑美元日线级(D1)θ模型 负责预测θ未来值的ONNX模型
欧元兑美元极坐标 用于分析MQL5脚本获取数据的Jupyter笔记本电脑

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/17085

最近评论 | 前往讨论 (4)
Too Chee Ng
Too Chee Ng | 27 3月 2025 在 10:41
喜欢
Aleksej Poljakov
Aleksej Poljakov | 17 11月 2025 在 15:38

你的建议有一个严重的缺陷。

公式 r=(x^2+y^2)^0.5 只有在 x 和 y 可通约的情况下才有效。也就是说,两个坐标轴上的单位是相同的。

在我们的例子中,x 轴上是时间,y 轴上是点。它们是不可通约的,你无法将秒转换成点。

这就是为什么你得到了一个荒谬的 180 度。也就是说,价格的方向是相反的--从现在到过去。如果你想要角度,可以建立线性回归 y = a*x+b。然后根据 a 的值推导出角度。然后将结果与圆形正态分布进行比较。这会很有趣。

Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana | 26 11月 2025 在 14:58
Too Chee Ng #:
喜欢
谢谢@Too Chee Ng
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana | 26 11月 2025 在 15:06
Aleksej Poljakov 线性回归 y = a*x+b。然后将结果与圆形正态分布进行比较。这会很有趣。
感谢@Aleksej Poljakov 的反馈。在这篇文章中,X 轴并不代表时间。x 轴是开盘价的历史值,y 轴是收盘价的历史值。因此,我并不完全理解您为什么说时间是在 x 轴上实现的。

不过,我并没有否定您的观点,应用数学是一个广阔的领域,我愿意与您进行讨论。

您提出的从 a 值推导角度的解决方案相当有趣,我很乐意听到您更多的意见。



Gamu。
价格行为分析工具包开发(第10部分):外部资金流(二)VWAP 价格行为分析工具包开发(第10部分):外部资金流(二)VWAP
通过我们的综合指南,掌握VWAP的强大力量!学习如何使用MQL5和Python将VWAP分析集成到您的交易策略中。最大化您的市场洞察力,并改善您今天的交易决策。
开发回放系统(第 78 部分):新 Chart Trade(五) 开发回放系统(第 78 部分):新 Chart Trade(五)
在本文中,我们将研究如何实现部分接收方代码。在这里我们将实现一个 EA 交易来测试和了解协议交互是如何工作的。此处提供的内容仅用于教育目的。在任何情况下,除了学习和掌握所提出的概念外,都不应出于任何目的使用此应用程序。
创建MQL5交易管理员面板(第九部分):代码组织(1) 创建MQL5交易管理员面板(第九部分):代码组织(1)
这次将深入探讨处理大型代码库时遇到的挑战。我们将探索在MQL5中进行代码组织的最佳实践,并采用一种实用方法来提升我们交易管理面板源代码的可读性和可扩展性。此外,我们致力于开发可复用的代码组件,这些组件有可能为其他开发者在其算法开发过程中带来益处。请继续阅读并参与讨论。
交易中的神经网络:搭配预测编码的混合交易框架(终篇) 交易中的神经网络:搭配预测编码的混合交易框架(终篇)
我们继续研习 StockFormer 混合交易系统,其结合了预测编码和强化学习算法,来分析金融时间序列。该系统基于三个变换器分支,搭配多样化多头注意力(DMH-Attn)机制,能够捕获资产之间的复杂形态、和相互依赖关系。之前,我们已领略了该框架的理论层面,并实现了 DMH-Attn 机制。今天,我们就来聊聊模型架构和训练。