MT5CTP项目受到大家的极大关注和积极测试、应用,始料未及。朋友们都反映积累了海量的mt4源代码,做mt5的代码转换都有点吃力,更不用说再修改到适配MT5CTP项目来直接驱动国内期货交易。源代码的最少改动原则是本项目初始的设计目标之一,当时是基于mt5源代码考虑,更多的朋友建议:目标应该是适配mt4源代码。好吧,回归项目初心,继续努力:MT4代码适配器(CTPMQL4)来了。

逻辑上,CTPMQL4是记录EA的持仓(报单)明细,MT5CTP是记录持仓汇总。持仓明细和持仓汇总之间需要对账,这是非常困难的,因为MT5CTP是一个开放的系统,持仓可以手动平仓,也可以外部软件平仓,CTPMQL4的持仓明细对此并不知情,CTPMQL4持仓明细更像是封闭系统。后来朋友们建议,在完美适配和海量代码的交易驱动之间选择,后者更为核心。

CTPMQL4记录持仓明细,并根据订单的状态自动更新,还需要做数据持久化,为此我们使用了数据库来达到这个目标,因为数据库操作关系持仓记录的安全和准确,所以如果数据库操作错误,CTPMQL4会发出Alert警告。数据库中数据表结构如下:

关键字段的说明:

ticket:是订单(报单)的系统唯一标识,用于标注分笔报单形成的持仓。原生系统这个字段来源于服务器,本项目中,我们使用了sqlite3数据库的rowid这个隐形字段,这个字段是自增长的行序号,而且是单调递增,可保证ticket本地唯一。

orderlots,openlots,closelots:三个数量分别用于表示持仓数量,开仓数量和平仓数量,一般来说,持仓数量是动态变化的,开仓数量和开仓数量是不变的,是初始报单的数量。也有特殊情况,比如撤单,报单错误,部分成交等等也会导致开仓数量和平仓数量的变化。这些变化不需要上层ea的关注,这些字段是用来组合判定是否是历史仓,是否已经完全成交等信息。比如:orderlots=0,openlots>0表示挂单尚未成交;orderlots>0,openlots>0,orderlots<openlots表示订单部分成交等等。CTP柜台信息发生变化的时候,这些字段也在同步变化,并实时记录到数据库,这部分说明,只是帮助您理解系统字段的作用和工作逻辑,对上层ea是隐藏的。

opensysid,closesysid:这两个字段是用来关联ea的报单和CTP柜台报单用的,用于响应CTP的报单回报信息。显然,非CTPMQL4的报单,不会得到关注。

其他的字段大家应该都会比较熟悉,需要说明的是持仓的部分平仓,一笔持仓部分平仓后,我们的CTPMQL4会更新原持仓记录为历史持仓,未平仓部分形成一笔新的持仓,这个新的持仓使用了新的ticket,即数据库新增了一条持仓记录。

如何实现mt4源代码的适配的呢?CTPMQL4使用了编译预处理功能,对mt4的接口函数函数、预定义变量、枚举变量等做了重定义,为此我们设计了一个类来打包。并在预处理开始的位置,实例化了类对象,因为编译预处理的限制,部分函数需要在mt4源代码中做显式调用,这些内容你都可以查看CTPMQL4源码找到对应的实现。特别需要声明的就是指数合约的直接驱动交易,需要在ea层做设计处理,我们试图在CTPMQL4中自动匹配处理这个问题,失败了。

CTPMQL4支持mt4的所有报单类型,包括limit单和stop单。因为MT5CTP项目暂不支持期权,所以没有实现mt4的OrderCloseBy函数。

CTPMQL4的设计理念、工作逻辑、架构和方法基本就是这样的,接下来我们介绍如何使用?开始修改mt4的源代码,直接驱动MT5CTP,总结下来就是五步,简单到不可思议。

第一步:在mt4源代码的最顶端,加上如下一段代码:

解释:定义__CTPMQL4__标识,打开CTPMQL4工作环境。

第二步:在OnTick回调函数的开始,加上如下一段代码:

解释:只需要红色框中的这一句。类中调用,主要的工作有三点,一是完成初始化;二是填充类中的数据;三是持仓的止损止盈。

第三步:增加窗口事件回调,可以在代码的最后,加上如下一段:

解释:CTPMQL4需要跟踪订单的变化,并同步更新数据库,记录明细持仓的状态,所以需要监听CTP的订单事件。

第四步:修改报单、平仓、撤单、订单修改这几个“主动”报单处理函数,做显式调用:

解释:所谓显示调用就是在将OrderSend,OrderClose,OrderModify和OrderDelete函数替换成mt4.OrderSend,mt4.OrderClose,mt4.OrderModify和mt4.OrderDelete 。主要原因是预编译处理器不支持函数嵌套,而我们使用这些函数的时候,往往会嵌套OrderTicket()等函数使用。

第五步:部分技术指标的显式调用和iCustom自定义指标调用的特殊处理。显式调用是因为预处理器支持的函数参数最多为8个,如果EA中调用的技术指标参数超过8个,你就需要显式的调用CTPMQL4,就是在函数前面加上前缀“mt4.”。iCustom比较特殊,是个不定参数的函数,而这个函数又是如此重要,如果不能有合理的解决方案,CTPMQL4的可用性就大打折扣,这的确费了些脑筋。我们给出的方案是需要在mt4的源代码中修改,使用MqlParam结构体数组将指标的参数填充好,然后再显性调用mt4.iCustom。需要说明的是,你只需要填充参数部分就好,缺失的部分CTPMQL4又进一步做了处理,你可以查看此部分代码,更深入的了解实现的方法。

一二三四五,简单修改就可以使用原mt4的海量代码,驱动MT5CTP进行国内的期货交易。CTPMQL4是开源的,你可以按照自己的方式完善,变成你自己的独一无二的驱动框架,独门秘籍,so cool!

CTPMQL4秉持MT5CTP项目的一贯原则:Free Is Power!

补充介绍:iCustom的使用方法

介绍文档中对iCustom和MqlParam结构体数组语焉不详,结合代码补充使用方法。假设我有一个自定义指标,名称为:myMA(已在mt5环境下重新编译无误):

//+------------------------------------------------------------------+
//|                                       Custom Moving Averages.mq4 |
//|                   Copyright 2005-2015, MetaQuotes Software Corp. |
//|                                              http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright   "2005-2015, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"
#property description "Moving Average"
#property strict#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot ExtAMABuffer
#property indicator_label1  "MA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//【固定格式】包含合约库文件/目录
#ifndef __CTPMQL4__#define __CTPMQL4__#include <mt5ctpmtctp.mqh>
#endif
//--- indicator parameters
input int            InpMAPeriod=13;        // Period
input int            InpMAShift=0;          // Shift
input ENUM_MA_METHOD InpMAMethod=MODE_SMA;  // Method
//--- indicator buffer
double ExtLineBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(void){string short_name;int    draw_begin=InpMAPeriod-1;
//--- indicator short nameswitch(InpMAMethod){case MODE_SMA  : short_name="SMA(";                break;case MODE_EMA  : short_name="EMA(";  draw_begin=0; break;case MODE_SMMA : short_name="SMMA(";               break;case MODE_LWMA : short_name="LWMA(";               break;default :        return(INIT_FAILED);}//--- check for inputif(InpMAPeriod<2)return(INIT_FAILED);//--- indicator buffers mappingSetIndexBuffer(0,ExtLineBuffer);
//--- initialization donereturn(INIT_SUCCEEDED);}
//+------------------------------------------------------------------+
//|  Moving Average                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,const int prev_calculated,const datetime &time[],const double &open[],const double &high[],const double &low[],const double &close[],const long &tick_volume[],const long &volume[],const int &spread[]){
//--- check for bars countif(rates_total<InpMAPeriod-1 || InpMAPeriod<2)return(0);
//--- counting from 0 to rates_totalArraySetAsSeries(ExtLineBuffer,false);ArraySetAsSeries(close,false);
//--- first calculation or number of bars was changedif(prev_calculated==0)ArrayInitialize(ExtLineBuffer,0);
//--- calculationswitch(InpMAMethod){case MODE_EMA:  CalculateEMA(rates_total,prev_calculated,close);        break;case MODE_LWMA: CalculateLWMA(rates_total,prev_calculated,close);       break;case MODE_SMMA: CalculateSmoothedMA(rates_total,prev_calculated,close); break;case MODE_SMA:  CalculateSimpleMA(rates_total,prev_calculated,close);   break;}
//--- return value of prev_calculated for next callreturn(rates_total);}
//+------------------------------------------------------------------+
//|   simple moving average                                          |
//+------------------------------------------------------------------+
void CalculateSimpleMA(int rates_total,int prev_calculated,const double &price[]){int i,limit;
//--- first calculation or number of bars was changedif(prev_calculated==0){limit=InpMAPeriod;//--- calculate first visible valuedouble firstValue=0;for(i=0; i<limit; i++)firstValue+=price[i];firstValue/=InpMAPeriod;ExtLineBuffer[limit-1]=firstValue;}elselimit=prev_calculated-1;
//--- main loopfor(i=limit; i<rates_total && !IsStopped(); i++)ExtLineBuffer[i]=ExtLineBuffer[i-1]+(price[i]-price[i-InpMAPeriod])/InpMAPeriod;
//---}
//+------------------------------------------------------------------+
//|  exponential moving average                                      |
//+------------------------------------------------------------------+
void CalculateEMA(int rates_total,int prev_calculated,const double &price[]){int    i,limit;double SmoothFactor=2.0/(1.0+InpMAPeriod);
//--- first calculation or number of bars was changedif(prev_calculated==0){limit=InpMAPeriod;ExtLineBuffer[0]=price[0];for(i=1; i<limit; i++)ExtLineBuffer[i]=price[i]*SmoothFactor+ExtLineBuffer[i-1]*(1.0-SmoothFactor);}elselimit=prev_calculated-1;
//--- main loopfor(i=limit; i<rates_total && !IsStopped(); i++)ExtLineBuffer[i]=price[i]*SmoothFactor+ExtLineBuffer[i-1]*(1.0-SmoothFactor);
//---}
//+------------------------------------------------------------------+
//|  linear weighted moving average                                  |
//+------------------------------------------------------------------+
void CalculateLWMA(int rates_total,int prev_calculated,const double &price[]){int        i,limit;static int weightsum;double     sum;
//--- first calculation or number of bars was changedif(prev_calculated==0){weightsum=0;limit=InpMAPeriod;//--- calculate first visible valuedouble firstValue=0;for(i=0;i<limit;i++){int k=i+1;weightsum+=k;firstValue+=k*price[i];}firstValue/=(double)weightsum;ExtLineBuffer[limit-1]=firstValue;}elselimit=prev_calculated-1;
//--- main loopfor(i=limit; i<rates_total && !IsStopped(); i++){sum=0;for(int j=0;j<InpMAPeriod;j++)sum+=(InpMAPeriod-j)*price[i-j];ExtLineBuffer[i]=sum/weightsum;}
//---}
//+------------------------------------------------------------------+
//|  smoothed moving average                                         |
//+------------------------------------------------------------------+
void CalculateSmoothedMA(int rates_total,int prev_calculated,const double &price[]){int i,limit;
//--- first calculation or number of bars was changedif(prev_calculated==0){limit=InpMAPeriod;double firstValue=0;for(i=0; i<limit; i++)firstValue+=price[i];firstValue/=InpMAPeriod;ExtLineBuffer[limit-1]=firstValue;}elselimit=prev_calculated-1;
//--- main loopfor(i=limit; i<rates_total && !IsStopped(); i++)ExtLineBuffer[i]=(ExtLineBuffer[i-1]*(InpMAPeriod-1)+price[i])/InpMAPeriod;
//---}
//+------------------------------------------------------------------+

调用的方式,直接给出代码如下:

//【固定格式】包含合约库文件/目录
#ifndef __CTPMQL4__#define __CTPMQL4__#include <mt5ctpmtctp.mqh>
#endif
//--- input indi name
input string             InpName="myMA.mq4";          // 自定义指标名称
//--- indicator parameters
input int                InpMAPeriod=13;        // Period
input int                InpMAShift=0;          // Shift
input ENUM_MA_METHOD     InpMAMethod=MODE_SMA;  // Method
// 全局变量/保存自定义指标参数及类型
MqlParam para[3];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{// 设置指标参数:3个   //参数1para[0].type = TYPE_INT;                     //参数类型para[0].integer_value = InpMAPeriod;         //参数值//参数2para[1].type = TYPE_INT;                     //参数类型para[1].integer_value = InpMAShift;          //参数值//参数3para[2].type = TYPE_INT;                     //参数类型para[2].integer_value = InpMAMethod;         //参数值return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{mt4.OnTick();//-- 调用自定义指标double my_ma = mt4.iCustom(NULL,0,InpName,para,0,0);double pre_my_ma = mt4.iCustom(NULL,0,InpName,para,0,1);// do...// 调用Print()|comment()函数,信息输出/检查是个好习惯
}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{mt4.OnChartEvent(id,lparam,dparam,sparam);
}
//+------------------------------------------------------------------+

自定义指标的调用难的不是参数表重整和EA调用,修改自定义指标到mt5中或许更复杂。困难的地方在于指标的编写表达方式mt4和mt5有很大的差异,很多函数的调用都是不一致的,另外就是指标中调用指标或函数,会成倍的增加版本升级的难度。

上次测试用demo也放到这里,仅供参考。

demo1:Moving Average

//+------------------------------------------------------------------+
//|                                               Moving Average.mq4 |
//|                   Copyright 2005-2014, MetaQuotes Software Corp. |
//|                                              http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright   "2005-2014, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"
#property description "Moving Average sample expert advisor"#ifndef __CTPMQL4__#define __CTPMQL4__#include <mt5ctpmtctp.mqh>
#endif#define MAGICMA  20131111
//--- Inputs
input double Lots          =0.1;
input double MaximumRisk   =0.02;
input double DecreaseFactor=3;
input int    MovingPeriod  =12;
input int    MovingShift   =6;
//+------------------------------------------------------------------+
//| Calculate open positions                                         |
//+------------------------------------------------------------------+
int CalculateCurrentOrders(string symbol){int buys=0,sells=0;
//---int orders = OrdersTotal();for(int i=orders-1;i>=0;i--){if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA){if(OrderType()==OP_BUY)  buys++;if(OrderType()==OP_SELL) sells++;}}
//--- return orders volumeif(buys>0) return(buys);else       return(-sells);}
//+------------------------------------------------------------------+
//| Calculate optimal lot size                                       |
//+------------------------------------------------------------------+
double LotsOptimized(){double lot=Lots;int    orders=OrdersHistoryTotal();     // history orders totalint    losses=0;                  // number of losses orders without a break
//--- select lot sizelot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);
//--- calcuulate number of losses orders without a breakif(DecreaseFactor>0){for(int i=orders-1;i>=0;i--){if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false){Print("Error in history!");break;}if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL)continue;//---if(OrderProfit()>0) break;if(OrderProfit()<0) losses++;}if(losses>1)lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);}
//--- return lot sizeif(lot<0.1) lot=0.1;return(lot);}
//+------------------------------------------------------------------+
//| Check for open order conditions                                  |
//+------------------------------------------------------------------+
void CheckForOpen(){double ma;int    res;
//--- go trading only for first tiks of new barif(Volume[0]>1) return;
//--- get Moving Average ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//--- sell conditionsif(Open[1]>ma && Close[1]<ma){res=mt4.OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"mtctp测试",MAGICMA,0,Red);return;}
//--- buy conditionsif(Open[1]<ma && Close[1]>ma){res=mt4.OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"mtctp测试",MAGICMA,0,Blue);return;}
//---}
//+------------------------------------------------------------------+
//| Check for close order conditions                                 |
//+------------------------------------------------------------------+
void CheckForClose(){double ma;
//--- go trading only for first tiks of new barif(Volume[0]>1) return;
//--- get Moving Average ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//---int orders = OrdersTotal();for(int i = orders-1;i>=0;i--){if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;//--- check order type if(OrderType()==OP_BUY){if(Open[1]>ma && Close[1]<ma){if(!mt4.OrderClose(OrderTicket(),OrderLots(),Bid,3,White))Print("OrderClose error ",GetLastError());}break;}if(OrderType()==OP_SELL){if(Open[1]<ma && Close[1]>ma){if(!mt4.OrderClose(OrderTicket(),OrderLots(),Ask,3,White))Print("OrderClose error ",GetLastError());}break;}}
//---}
//+------------------------------------------------------------------+
//| OnTick function                                                  |
//+------------------------------------------------------------------+
void OnTick(){mt4.OnTick();
//--- check for history and tradingif(Bars<100 || IsTradeAllowed()==false)return;
//--- calculate open orders by current symbolif(CalculateCurrentOrders(Symbol())==0) CheckForOpen();else                                    CheckForClose();
//---}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam){mt4.OnChartEvent(id,lparam,dparam,sparam);}
//+------------------------------------------------------------------+

demo2:MACD Sample

//+------------------------------------------------------------------+
//|                                                  MACD Sample.mq4 |
//+------------------------------------------------------------------+
#ifndef __CTPMQL4__#define __CTPMQL4__#include <mt5ctpmtctp.mqh>
#endifinput double TakeProfit    =50;
input double Lots          =0.1;
input double TrailingStop  =30;
input double MACDOpenLevel =3;
input double MACDCloseLevel=2;
input int    MATrendPeriod =26;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick(void){mt4.OnTick();double MacdCurrent,MacdPrevious;double SignalCurrent,SignalPrevious;double MaCurrent,MaPrevious;int    cnt,ticket,total;
//---
// initial data checks
// it is important to make sure that the expert works with a normal
// chart and the user did not make any mistakes setting external
// variables (Lots, StopLoss, TakeProfit,
// TrailingStop) in our case, we check TakeProfit
// on a chart of less than 100 bars
//---if(Bars<100){Print("bars less than 100");return;}if(TakeProfit<10){Print("TakeProfit less than 10");return;}
//--- to simplify the coding and speed up access data are put into internal variablesMacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);total=OrdersTotal();if(total<1){//--- no opened orders identifiedif(AccountFreeMargin()<(1000*Lots)){Print("We have no money. Free Margin = ",AccountFreeMargin());return;}//--- check for long position (BUY) possibilityif(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious){ticket=mt4.OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);if(ticket>0){if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))Print("BUY order opened : ",OrderOpenPrice());}elsePrint("Error opening BUY order : ",GetLastError());return;}//--- check for short position (SELL) possibilityif(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious){ticket=mt4.OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"macd sample",16384,0,Red);if(ticket>0){if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))Print("SELL order opened : ",OrderOpenPrice());}elsePrint("Error opening SELL order : ",GetLastError());}//--- exit from the "no opened orders" blockreturn;}
//--- it is important to enter the market correctly, but it is more important to exit it correctly...   for(cnt=0;cnt<total;cnt++){if(!OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES))continue;if(OrderType()<=OP_SELL &&   // check for opened position OrderSymbol()==Symbol())  // check for symbol{//--- long position is openedif(OrderType()==OP_BUY){//--- should it be closed?if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MacdCurrent>(MACDCloseLevel*Point)){//--- close order and exitif(!mt4.OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet))Print("OrderClose error ",GetLastError());return;}//--- check for trailing stopif(TrailingStop>0){if(Bid-OrderOpenPrice()>Point*TrailingStop){if(OrderStopLoss()<Bid-Point*TrailingStop){//--- modify order and exitif(!mt4.OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green))Print("OrderModify error ",GetLastError());return;}}}}else // go to short position{//--- should it be closed?if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point)){//--- close order and exitif(!mt4.OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet))Print("OrderClose error ",GetLastError());return;}//--- check for trailing stopif(TrailingStop>0){if((OrderOpenPrice()-Ask)>(Point*TrailingStop)){if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0)){//--- modify order and exitif(!mt4.OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red))Print("OrderModify error ",GetLastError());return;}}}}}}
//---}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam){mt4.OnChartEvent(id,lparam,dparam,sparam);}
//+------------------------------------------------------------------+

如何查看eas源代码_MT5CTP扩展:MT4源代码(EA)适配器来了相关推荐

  1. 谷歌浏览器怎么查看网页源代码 Chrome浏览器网页源代码查看技巧分享

    凭借简单.高效的使用体验,谷歌开发的网页浏览器"Chrome"在国内也不乏粉丝,甚至一度被视为装机必备的软件之一.但其操作方式和界面设计,与国产浏览器略有不同!那么,谷歌浏览器要怎 ...

  2. java 企业号 临时素材_查看“获取临时素材文件”的源代码

    因为以下原因,你没有权限编辑本页: 您刚才请求的操作只对以下1个用户组开放:用户. 您可以查看并复制此页面的源代码: 通过media_id获取图片.语音.视频等文件,协议和普通的http文件下载完全相 ...

  3. 口袋妖怪php源码,查看“主题:宝可梦”的源代码

    因为以下原因,您没有权限编辑本页: 您所请求的操作仅限于该用户组的用户使用:用户 您可以查看与复制此页面的源代码.{{PortalPage |category=宝可梦 |header = {{Port ...

  4. 修马达的php源码,查看SKU:RB-02S087 振动马达模块的源代码

    因为以下原因,你没有权限编辑本页: 您刚才请求的操作只有这个用户组中的用户才能使用: 用户 您可以查看并复制此页面的源代码:[[文件:02S08701.png|500px|缩略图|右]] ==产品概述 ...

  5. 如何查看Androidstudio中activity_main.xml的源代码

    如何查看Androidstudio中activity_main.xml的源代码 首先打开Androidstudio中activity_main.xml,如图所示: 当你想要查看代码时确不知道在哪里找, ...

  6. 樱花源代码_查看“完全墨染的樱花”的源代码

    因为以下原因,您没有权限编辑本页: 您所请求的操作仅限于该用户组的用户使用:少女 您可以查看与复制此页面的源代码.=== 东方妖妖梦 === {| |- | [[文件:{{西行寺幽幽子符卡名|1|YY ...

  7. 如何查看python源代码_查看“使用python做图像处理”的源代码

    因存在冲突的中间编辑,本编辑不能撤销. 因为以下原因,您没有权限编辑本页: 您所请求的操作仅限于该用户组的用户使用:用户 您可以查看和复制此页面的源代码.==安装python程序包mahotas== ...

  8. SVN-项目 XXX 受源代码管理。向源代码管理注册此项目时出错。建议不要对此项目进行任何修改...

    错误描述:  项目 XXX 受源代码管理.向源代码管理注册此项目时出错.建议不要对此项目进行任何修改 解决办法: 使用记事本打开,项目csproj文件删除图中几行,重新打开解决方案就可以了 原因分析: ...

  9. 如何高效的阅读Hadoop源代码?Hadoop的源代码写的怎么样?

    个人谈谈阅读hadoop源代码的经验. 首先,不得不说,hadoop发展到现在这个阶段,代码已经变得非常庞大臃肿,如果你直接阅读最新版本的源代码,难度比较大,需要足够的耐心和时间,所以,如果你觉得认真 ...

最新文章

  1. Java 内存模型 JMM 详解
  2. 消息推送生命周期_一套完整的APP推送体系方案|附思维导图
  3. stm32 输入捕获 测量脉宽
  4. python输出矩阵的行数_python查看矩阵的行列号以及维数方式
  5. 剑指offer51 构建乘积数组(图解)
  6. php代码怎么看错在哪里,PHP代码不知道哪里错了。
  7. eclipse 离线安装python开发工具 PyDev
  8. 集合框架之ArrayList集合
  9. notepad++弹出菜单
  10. Qt开源作品43-超级图形字体
  11. 微商怎么引流被加精准粉?微商有效引流被加方法
  12. 玩转Safari:扩展插件说明
  13. 游轮旅游是三亚旅游的未来
  14. 360路由器故障显示DNS服务器,360安全路由器dns异常解决方法
  15. 小白以及计算机类学生的福音!java查看内存溢出的工具
  16. 任务驱动在中职计算机课中的应用,论任务驱动教学法在中职计算机基础课上的应用...
  17. 【ELM预测】基于粒子群算法改进极限学习机ELM实现数据预测matlab源码
  18. 心跳包(确保连接的有效性)
  19. WuThreat身份安全云-TVD每日漏洞情报-2023-01-31
  20. PS图片无法保存ICO格式解决方法

热门文章

  1. python替换字符的操作_Python 字符串操作(string替换、删除、截取、复制、)
  2. Oracle使用impdb/expdb数据泵导入/导出数据库
  3. python含金量最高的考试_中国最难的五大考试,第二个含金量最高,考过年薪30万起!...
  4. dofilter 无效_“鹅厂”商标注册成功,腾讯异议无效
  5. 数据合并之concat、append、merge和join
  6. 在穷学生面前 “ 摆弄骚姿 ”,最美90后支教女老师翻车~!这TM就是所谓的 “ 支教媛 ” ~?...
  7. 肝货满满!CV学习笔记:入坑必备
  8. 浙大提出会打德扑的「自我博弈」AI,还会玩射击游戏
  9. PHP大批量正则,php – 正则表达式匹配无限数量的选项
  10. linux怎么创建扩展分区,Linux磁盘创建扩展分区