English Español Deutsch 日本語 Português
preview
结合基本面和技术分析策略在MQL5中的实现(适合初学者)

结合基本面和技术分析策略在MQL5中的实现(适合初学者)

MetaTrader 5示例 | 17 二月 2025, 10:27
94 0
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

引言

基本面分析和趋势跟踪策略通常被视为对立的方法。许多偏好基本面分析的交易者认为技术分析是浪费时间,因为所有必要的信息已经反映在价格中。相反,技术分析者常常认为基本面分析存在缺陷,因为相同的模式(如头肩顶)在同一个市场中可能导致不同的结果。

对于新交易者来说,这可能会让人感到不知所措,因为您面临着众多选择,但哪一种才是最好的呢?哪种策略能够在不利条件下让您保持盈利,同时让您在市场不佳时避开风险?

作为作者,我相信真相介于两者之间。本文的目的是探索我们是否可以创建一个稳定的交易策略,结合基本面和技术分析的最佳方面,并确定这种策略是否值得投入时间。

我们将从头开始使用原生的MQL5构建我们的EA,这使我们能够灵活地在任何市场上测试我们的策略。到本文结束时,您将了解:

  1. 如何在MQL5中构建自己的EA。
  2. 如何结合多种技术指标。
  3. 一个用于概念化基本面和技术数据的框架。 


交易策略概览

我们的交易策略由两个组成部分:

  1. 基本面分析
  2. 技术分析

让我们依次考虑每种方法,以了解它们是如何相互补充的,而不是试图确定哪一种更优越。我们将从理解推动我们策略的基本原则开始。

乍一看,金融图表可能显得非常随机且不可预测。金融数据集以嘈杂著称,有时甚至不稳定。然而,从基本面的角度分析这些图表可能会得出关于市场行为的完全不同的结论。


基本面分析

基本面分析基于对市场运作方式的理解。在我们的讨论中,我们将专注于货币对,并构建我们的交易算法以利用我们对外汇市场及其主要参与者的理解。

金融数据

图1:AUDJPY货币对的基本面分析示例。



基本面交易者经常讨论支撑和阻力,尽管这些概念并没有明确的定义。我想从基本面的角度提供一种可能的解释。

当我们观察两种货币之间的汇率时,很容易忘记其实际影响。例如,如果USDJPY图表上升,这意味着日元相对于美元正在贬值。由于世界上90%的商品都以美元计价,因此汇率上升表明日本的出口在国外获得的收入减少。

如果汇率无限制地持续上升,日本政府将面临重大挑战。他们的出口将变得一文不值,导致经济压力和生活水平下降。家庭可能难以负担生活必需品,国家可能面临恶性通货膨胀和严峻的经济状况。

为了避免这种结果,对日本的福祉至关重要的是,日元与美元之间的汇率必须保持在可接受的范围内。当汇率过高时,日本政府有动机干预外汇市场以保护其经济。相反,当汇率过低时,美国政府可能会提供支持以维持平衡。这就是从基本面角度对支撑和阻力的解释。

在大多数情况下,外汇汇率是由大型金融机构(如零售银行、投资银行和对冲基金)的集体决策决定的。这些金融巨头控制着大量的资金,它们的集体决策推动了市场。

因此,从基本面的角度来看,我们不想与大型企业参与者进行反向交易,而是更愿意寻找与主导市场参与者同方向交易的机会。

通过分析较高时间框架(如周线或月线)上的价格变化,我们可以了解大型机构参与者认为被观察证券的公平价格水平是什么。因此,我们将寻找与长期价格变化一致的交易机会。

将所有内容整合在一起,我们的基本面策略涉及以下几个步骤。首先,我们将分析更高时间框架,以了解机构参与者可能将价格带到何处。一旦确认,我们将通过检查前一周的最高价和最低价来确定我们的支撑位和阻力位。我们的目标是交易高概率的设置,因此如果价格突破阻力位,我们将买入头寸。相反,如果价格跌破支撑位,我们将卖出头寸。


技术分析

现在,我们将定义我们交易策略中涉及的技术分析。我们的技术分析专注于识别我们的指标与基本面分析一致的交易设置。这意味着,如果更高时间框架上的趋势是看涨的,我们只寻找我们的技术指标发出做多信号的设置。相反,如果更高时间框架上的趋势是看跌的,我们只寻找我们的指标与做空交易一致的设置。

我们组合中的第一个指标是资金流量指数(MFI)。MFI作为成交量指标,在我们的策略中起着关键作用。我们只考虑有显著成交量支持的交易。成交量弱或相反的交易不在我们的考虑范围内。在我们的策略中,我们对MFI的解读与传统方法不同。我们将MFI以50为中心:读数低于50表示看跌成交量,而读数高于50表示看涨成交量。

接下来,我们使用移动平均收敛发散指标(MACD)。与我们对MFI的处理方式类似,我们并不以传统方式使用MACD。相反,我们将MACD以0为中心。MACD信号线低于0表示看跌趋势,而信号线高于0则表示看涨趋势。

除了MFI和MACD之外,我们的策略还采用经典的移动平均线趋势跟踪方法。与其他技术指标不同,我们对移动平均线的解读是传统的:如果价格低于移动平均线,则发出卖出信号;如果价格高于移动平均线,则发出买入信号。
此外,我们将随机振荡器整合到我们的策略中,并遵循其传统解读。当振荡器读数高于20时,我们将其解释为买入信号。相反,振荡器读数低于80则表示卖出信号。

因此,如果我们买入:

  1. 收盘价必须在移动平均线之上
  2. MACD指标大于0
  3. MFI读数大于50
  4. 随机振荡器应高于20
  5. 价格在过去3个月内必须上涨。
  6. 价格水平应高于支撑位。

反之,若要卖出一种证券:

  1. 价格必须收于移动平均线之下。
  2. MACD信号应低于0。
  3. MFI读数应小于50。
  4. 随机振荡器应低于80。
  5. 价格在过去3个月内必须下跌。
  6. 价格水平应在阻力位之下。

让我们开始吧。

首先,我们导入所需的库。在这种情况下,我们将导入交易库以执行交易指令。

//+------------------------------------------------------------------+
//|                           Price Action & Trend Following.mq5     |
//|                        Copyright 2024, MetaQuotes Ltd.           |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Zororo Ndawana"
#property link      "https://www.mql5.com"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
/*
     该智能交易系统(Expert Advisor)将帮助我们结合基本面分析
     和趋势跟踪原则,以精确交易金融证券。
     这得益于易于学习的MQL5语言,它为我们提供了创造性灵活性
     和技术控制的完美结合。

     我们的基本面策略遵循以下原则:
     1)尊重更高时间框架上的价格走势
     2)在支撑位入场,在阻力位出场
     我们的趋势跟踪策略遵循经过时间验证的原则:
     1)只在有成交量支持的条件下入场交易
     2)不逆主导趋势交易,而是等待与更大趋势一致的交易机会。
   3)使用一组公认的优质指标

   Gamuchirai Zororo Ndawana
   Selebi Phikwe
   Botswana
   11:06 Thursday 11 July 2024
*/

//+------------------------------------------------------------------+
//| Include necessary libraries                                      |
//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>
CTrade Trade;

继续进行下去,我们现在需要为我们的程序定义输入。这些输入将控制我们技术指标的周期、期望的交易手数以及其他类似性质的变量。

//+------------------------------------------------------------------+
//| Input parameters for technical indicators                        |
//+------------------------------------------------------------------+
input int stoch_percent_k = 5; // Stochastic %K
input int stoch_percent_d = 3; // Stochastic %D
input int stoch_slowing   = 3; // Stochastic Slowing

input int macd_fast_ema = 12; // MACD Fast EMA
input int macd_slow_ema = 26; // MACD Slow EMA
input int macd_sma = 9;       // MACD SMA

input int ma_period = 60; // Moving Average Period
input int mfi_period = 14; // MFI Period

input int lot_multiple = 10; // Lot size multiplier

现在我们要创建用于整个程序的全局变量。这些变量将存储我们的支撑位和阻力位、技术指标缓冲区、买价和卖价以及其他类似的信息。

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
double ask, bid;               // Ask and Bid prices
double min_distance = 0.2;     // Minimum distance for stoploss
double min_lot_size = 0;       // Minimum lot size
double position_size;          // Actual position size

double last_week_high = 0;     // High of the previous week
double last_week_low = 0;      // Low of the previous week

string last_week_high_name = "last week high"; // Name for high level object
string last_week_low_name = "last week low";   // Name for low level object

double higher_time_frame_change = 0.0; // Change on higher time frame
string zone_location = "";             // Current zone location

int zone = 0;                // Zone indicator
string higher_time_frame_trend = ""; // Higher time frame trend
int trend = 0;               // Trend indicator

int ma_handler, stoch_handler, macd_handler, mfi_handler; // Handlers for indicators
double ma_reading[], stoch_signal_reading[], macd_signal_reading[], mfi_reading[]; // Buffers for indicator readings

我们现在的目标是定义我们的OnInit()处理程序,在这个函数中,我们将初始化我们的技术指标,并适当地调整我们的交易手数。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set up handlers for technical indicators
   ma_handler = iMA(_Symbol, PERIOD_CURRENT, ma_period, 0, MODE_EMA, PRICE_CLOSE);
   macd_handler = iMACD(_Symbol, PERIOD_CURRENT, macd_fast_ema, macd_slow_ema, macd_sma, PRICE_CLOSE);
   stoch_handler = iStochastic(_Symbol, PERIOD_CURRENT, stoch_percent_k, stoch_percent_d, stoch_slowing, MODE_EMA, STO_CLOSECLOSE);
   mfi_handler = iMFI(_Symbol, PERIOD_CURRENT, mfi_period, VOLUME_TICK);

//--- Adjust lot size
   min_lot_size = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   position_size = min_lot_size * lot_multiple;

//--- Initialization done
   return(INIT_SUCCEEDED);
  }

接下来,我们将定义一个函数,用于获取上周交易历史所确定的支撑位和阻力位。

//+------------------------------------------------------------------+
//| Function to get the previous week's high and low prices          |
//+------------------------------------------------------------------+
bool get_last_week_high_low(void)
  {
//--- Reset values
   last_week_high = 0;
   last_week_low = 0;

//--- Remove old levels if any
   ObjectDelete(0, last_week_high_name);
   ObjectDelete(0, last_week_low_name);

//--- Update high and low values
   last_week_high = iHigh(_Symbol, PERIOD_W1, 1);
   last_week_low = iLow(_Symbol, PERIOD_W1, 1);

//--- Mark current levels of support and resistance
   ObjectCreate(0, last_week_high_name, OBJ_HLINE, 0, 0, last_week_high);
   ObjectCreate(0, last_week_low_name, OBJ_HLINE, 0, 0, last_week_low);

//--- Check for valid values
   return((last_week_high * last_week_low) != 0);
  }

继续进行下去,我们需要理解更高时间框架上发生的价格走势。请记住,我们将回顾过去的一个交易周期,大约3个月,以推断机构参与者在市场中的行为。

//+------------------------------------------------------------------+
//| Function to determine higher time frame price movement           |
//+------------------------------------------------------------------+
bool get_higher_time_frame_move(void)
  {
//--- Analyze weekly time frame
   higher_time_frame_change = iClose(_Symbol, PERIOD_CURRENT, 1) - iClose(_Symbol, PERIOD_W1, 12);

//--- Check for valid values
   return((iClose(_Symbol, PERIOD_W1, 12) * iClose(_Symbol, PERIOD_W1, 1)) != 0);
  }

我们接下来的任务是解读我们收集到的价格走势信号。特别是,我们需要了解我们是否高于上周的最高价,我们将这称为1区;或者我们是否低于上周的最低价,那么我们处于3区;最后,如果我们介于两者之间,那么我们处于2区。然后,我们将标记我们在更高时间框架上识别出的趋势,如果价格在更高时间框架上上涨,我们将趋势标记为1;否则,我们将趋势标记为-1。

//+------------------------------------------------------------------+
//| Function to interpret price action data                          |
//+------------------------------------------------------------------+
void interpet_price_action(void)
  {
//--- Determine zone location based on last week's high and low
   if(iClose(_Symbol, PERIOD_CURRENT, 0) > last_week_high)
     {
      zone = 1;
      zone_location = "We are above last week's high";
     }
   else if(iClose(_Symbol, PERIOD_CURRENT, 0) < last_week_low)
     {
      zone = 3;
      zone_location = "We are below last week's low";
     }
   else
     {
      zone = 2;
      zone_location = "We are stuck inside last week's range";
     }

//--- Determine higher time frame trend
   if(higher_time_frame_change > 0)
     {
      higher_time_frame_trend = "Higher time frames are in an up trend";
      trend = 1;
     }
   else if(higher_time_frame_change < 0)
     {
      higher_time_frame_trend = "Higher time frames are in a down trend";
      trend = -1;
     }
  }

现在我们需要一个函数,用于更新我们的技术指标值并获取当前市场数据。

//+------------------------------------------------------------------+
//| Function to update technical indicators and fetch market data    |
//+------------------------------------------------------------------+
void update_technical_indicators(void)
  {
//--- Update market prices
   ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

//--- Copy indicator buffers
   CopyBuffer(ma_handler, 0, 1, 1, ma_reading);
   CopyBuffer(stoch_handler, 1, 1, 1, stoch_signal_reading);
   CopyBuffer(macd_handler, 1, 1, 1, macd_signal_reading);
   CopyBuffer(mfi_handler, 0, 1, 1, mfi_reading);
  }

如果我们的看跌情绪函数允许,这个函数将为我们执行交易入场,我们将开启一个卖出交易。相反,只有在我们的看涨情绪函数允许的情况下,我们才能开启买入头寸。

//+------------------------------------------------------------------+
//| Function to find entry points for trades                         |
//+------------------------------------------------------------------+
void find_entry(void)
  {
//--- Check for bullish sentiment
   if(bullish_sentiment())
     {
      Trade.Buy(position_size, _Symbol, ask, (last_week_low - min_distance), (last_week_high + min_distance));
     }
//--- Check for bearish sentiment
   else if(bearish_sentiment())
     {
      Trade.Sell(position_size, _Symbol, bid, (last_week_high + min_distance), (last_week_low - min_distance));
     }
  }

现在,让我们仔细定义我们的两个交易系统对齐以形成买入设置的含义。回想我们在前面讨论中定义的条件,我们希望看到价格收于移动平均线之上,我们的MFI指标应高于50,我们的MACD读数应高于0,随机振荡器应高于20,更高时间框架上的趋势应为看涨,且我们应处于支撑位之上。

//+------------------------------------------------------------------+
//| Function to analyze bullish signals                              |
//+------------------------------------------------------------------+
bool bullish_sentiment(void)
  {
//--- Analyze conditions for bullish sentiment
   return((mfi_reading[0] > 50) &&
          (iClose(_Symbol, PERIOD_CURRENT, 1) > ma_reading[0]) &&
          (macd_signal_reading[0] > 0) &&
          (stoch_signal_reading[0] > 20) &&
          (trend == 1) &&
          (zone < 3));
  }

对于我们的卖出设置,情况则完全相反。

//+------------------------------------------------------------------+
//| Function to analyze bearish signals                              |
//+------------------------------------------------------------------+
bool bearish_sentiment(void)
  {
//--- Analyze conditions for bearish sentiment
   return((mfi_reading[0] < 50) &&
          (iClose(_Symbol, PERIOD_CURRENT, 1) < ma_reading[0]) &&
          (macd_signal_reading[0] > 0) &&
          (stoch_signal_reading[0] < 80) &&
          (trend == -1) &&
          (zone > 1));
  }

最后,我们需要一个OnTick()事件处理程序,以确保我们应用程序中的事件流程按照我们的意图运行。请注意,我们首先检查时间戳,这有助于确保我们的应用程序每周只检查一次支撑位和阻力位。否则,如果没有新的周线蜡烛图,那么在每个tick上反复检查相同的信息是没有意义的!如果一切正常,那么我们的专家顾问将接着解释价格走势,更新我们的技术指标,然后寻找交易入场机会。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Check for new candle on higher time frame
   static datetime time_stamp;
   datetime current_time = iTime(_Symbol, PERIOD_W1, 0);

   if(time_stamp != current_time)
     {
      time_stamp = current_time;

      if(!get_last_week_high_low())
        {
         Print("Failed to get historical performance of ", _Symbol);
         Print("[ERROR]: ", GetLastError());
        }
      else if(!get_higher_time_frame_move())
        {
         Print("Failed to analyze historical performance of ", _Symbol);
         Print("[ERROR]: ", GetLastError());
        }
     }
   else
     {
      interpet_price_action();
      update_technical_indicators();
      if(PositionsTotal() == 0)
        {
         find_entry();
        }
      Comment("Last week high: ", last_week_high, "\nLast week low: ", last_week_low, "\nZone: ", zone_location, "\nTrend: ", higher_time_frame_trend);
     }
  }


运行我们的程序

图2:我们的EA在H1时间框架上交易AUDJPY

运行我们的程序

图3:在AUDJPY符号的H1数据上对我们的交易算法进行1个月的回测结果


结论

本文展示了如何在交易策略中整合基本面和技术分析。通过使用MQL5,我们展示了如何将这两个视角的洞察力无缝结合成可操作的交易指令。通过提供一个基本面和技术数据相互补充而非竞争的框架,我们赋予读者有效利用这两种方法的能力。


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

附加的文件 |
从基础到中级:变量(II) 从基础到中级:变量(II)
今天,我们将探讨如何使用静态变量。这个问题常常让许多程序员感到困惑,无论是初学者还是有一定经验的开发者,因为使用这一机制时需要遵循一些特定的建议。本文旨在为教学目的提供材料。在任何情况下,应用程序都应仅用于学习和掌握所介绍的概念。
从基础到中级:变量(I) 从基础到中级:变量(I)
许多初学者很难理解为什么他们的代码没有按他们预期的方式运行。让代码真正发挥作用的因素有很多。代码能够正常运行,不仅仅是因为它包含了一系列不同的函数和操作。今天,我邀请您学习如何正确地编写真正的代码,而不是简单地复制粘贴代码段。这里呈现的材料仅供教学目的。在任何情况下,这些应用不应该被用于学习和掌握所介绍概念之外的其他目的。
重塑经典策略(第二部分):布林带突破 重塑经典策略(第二部分):布林带突破
本文探讨了一种将线性判别分析(LDA)与布林带相结合的交易策略,利用对市场区域的分类预测来生成战略性入场信号。
您应当知道的 MQL5 向导技术(第 21 部分):配以财经日历数据进行测试 您应当知道的 MQL5 向导技术(第 21 部分):配以财经日历数据进行测试
默认情况下,财经日历数据在策略测试器中不可用于智能系统测试。我们看看数据库能如何提供帮助,绕过这个限制。故此,在本文中,我们会探讨如何使用 SQLite 数据库来存档财经日历新闻,如此这般,由向导组装的智能系统就可以用它来生成交易信号。