屌丝命苦,拼爹拼不过,拼后台没有,技术宅一枚,情商有问题,不会见人说人话见鬼说鬼话,所以在国庆熬着混着,工作也没啥大起色,想想就郁闷,难不成一辈子就只能这样了?

苦思冥想,想得一条路,那就是程序化交易--现在程序化交易正有越来越火的趋势,国外已经程序化了很久,国内各大交易所也正在半掩半遮的开展,卷商、私人公司陆陆续续都在开展,心水啊,想着先研究研究,熟了之后也是碗饭啊,不行就靠着给人写策略也能吃口饭不至于饿死吧,想想还有点小鸡冻啊。

说干就干啊,原来做过外汇的模拟盘,用过MT4软件,软件自带MQL4语言,程序化已经支持的非常好了,还带有例子,还有高大上的名字叫EA,于是咱也高大上了一把,这年头都得将B格嘛。另外,选择外汇是因为外汇受认为操控的可能性比较小,外汇交易每天几万亿美元,不是个人能左右的了的。外汇里面,EUR/USD又是流通量最大的,所以就选择这个汇对。

废话了一大堆,直接在例子上改,开始是基于均线的MASample,运行了几个礼拜,不是很好,又在MACDSample上改了改,运行了个把月,基本上盈亏平衡,也算是个好开端吧。下面就是我该的macdSample的代码。

MQL4是一个类似c的语言,很多都可以按照c的逻辑来写。我定义的一些全局变量

 input double TakeProfit    =1000;
input double Lots =0.1;
input double TrailingStop =150;
input double MACDOpenLevel =5;
input double MACDCloseLevel=3;
input int MATrendPeriod =60;
input int MATrendPeriodFast =26;
input double MaximumRisk =0.08;
input double DecreaseFactor=3;
input int CheckPeriod = 36;

根据历史盈亏状况改变下单数量的函数,思路是:在最大下单数量的基础上*风险系数,如果有损失,损失次数/3,直到最小下单数量。不过最近也没用这个函数,主要是函数总是在几次损失后下最小的数量单子,但是行情总是在几次震荡才启动,所以总是错失良机,现在基本上都是下固定数量。

 //+------------------------------------------------------------------+
//| Calculate optimal lot size |
//+------------------------------------------------------------------+
double LotsOptimized()
{
double lot=Lots;
int orders=HistoryTotal(); // history orders total
int losses=0; // number of losses orders without a break
Print("value of Lots:",lot);
//--- select lot size
lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);
//--- calcuulate number of losses orders without a break
if(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 size
if(lot<0.1) lot=0.1;
Print("lot:",lot);
return(lot);
}

下面的函数是判断盘整行情的,主要是因为往往美国收市后,整个市场就波动很小了,等待第二天才会开始新一轮行情。

 //判断从第i个行情之前的一段时间内存在盘整行情
//盘整行情的定义:行情波动不大
bool hasConsolidation(int i)
{ double macd;
int count,j;
for(j=0;j<2*CheckPeriod;j++)
{
macd=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,i+j);
if(MathAbs(macd)<=(MACDOpenLevel*Point))
{
count=count+1;
if(count>=CheckPeriod)
{
Print("isConsolidation:",2*CheckPeriod,"个周期内有连续半数以上波动过小");
return true;
}
}else{
count = 0;
}
}
return false;
}

MACD的基础理论来了,金叉和死叉的应用(关于MACD以及金叉死叉,这里不解释,请各位自行百度或者知乎),我这里判断一段时间内是否有金叉或者死叉,太长时间也没啥意义,我主要是基于5分钟线做日内交易。

 //检查一小时内是否有金叉
bool CheckForGoldInHour()
{
double MacdCurrent,MacdPre,SignalCurrent,SignalPre;
for(int i=0;i<CheckPeriod;i++)
{
MacdCurrent=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,i);
MacdPre=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,i+1);
SignalCurrent=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,i);
SignalPre=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,i+1); //在0轴下的金叉
if(CheckForGold(MacdCurrent,MacdPre,SignalCurrent,SignalPre))
return true;
} return false;
} bool CheckForDeathInHour()
{
double MacdCurrent,MacdPre,SignalCurrent,SignalPre;
for(int i=0;i<CheckPeriod;i++)
{
MacdCurrent=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,i);
MacdPre=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,i+1);
SignalCurrent=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,i);
SignalPre=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,i+1); //在0轴上的死叉.
if(CheckForDeath(MacdCurrent,MacdPre,SignalCurrent,SignalPre))
return true;
} return false;
} bool CheckForGold(double MacdCurrent,double MacdPrevious,double SignalCurrent,double SignalPrevious)
{
if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
MathAbs(MacdCurrent)>(MACDOpenLevel*Point))
{
Print("在0轴下的金叉");
return true;
} return false;
} bool CheckForDeath(double MacdCurrent,double MacdPrevious,double SignalCurrent,double SignalPrevious)
{
if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
MacdCurrent>(MACDOpenLevel*Point))
{
Print("在0轴上的死叉");
return true;
} return false;
}

所有的策略最后都归结到一点,你是看多还是看空,看多,平掉空单,开多单,看空,平掉多单,开空单,简单的逻辑。

 double Macd0,Macd1,Macd2;
double Signal0,Signal1,Signal2;
double Ma0,Ma1,Ma2;
double highLevel; // 看前三个macd值和signal,都是向上的,并且均线向上
bool CheckForLong()
{
Macd0=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,0);
Macd1=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,1);
Macd2=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,2); Signal0=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,0);
Signal1=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,1);
Signal2=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,2); if(Macd1>=Macd0 || Macd2>=Macd1 || Signal1>=Signal0 || Signal2>=Signal1)
{
Print("CheckForLong:macd或者signal不是向上");
return false;
} highLevel = (Macd0+Macd1+Macd2-Signal0-Signal1-Signal2)/3; if(highLevel<MACDOpenLevel*Point)//Macd0<=(Signal0+MACDOpenLevel*Point) || Macd1<=(Signal1+MACDOpenLevel*Point) || Macd2<=(Signal2+MACDOpenLevel*Point))
{
Print("CheckForLong:macd不满足开仓必须高于信号足够的量");
Print("相差",highLevel/Point,"个Point");
return false;
} //均线变动比较慢,暂时取两个
Ma0=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
Ma1=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
//Ma2=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,2);
if(Ma0<Ma1)// || Ma1<Ma2)
{
Print("CheckForLong:均线向下,没有向上");
return false;
} if(!CheckForGoldInHour())
{
Print("CheckForLong:有效时间内没有检测到0轴下的金叉");
if(hasConsolidation(0))
{
Print("CheckForLong:检测到盘整行情,现在已经确定走势,可以开仓。");
return true;
}
return false;
} //if(Macd0>Macd1 && Macd1>Macd2 && Signal0>Signal1 && Signal1>Signal2 &&
// Macd0>(Signal0+MACDOpenLevel*Point) && Macd1>(Signal1+MACDOpenLevel*Point) && Macd2>(Signal2+MACDOpenLevel*Point)
// && Ma0>Ma1)
//{
//检查一小时内有金叉
// if(CheckForGoldInHour())
// return true;
//} //Print("CheckForLong:long");
return true;
}

这里面加入了均线的判断,macd本质上就是依据两条不同步调(比如我选择的26日均线和60日均线)的均线,如果快的均线离慢均线越来越近,则代表行情可能结束。但是在实际情况中,经常会是,快均线在超过慢均线快速上涨之后,慢慢回落到慢均线,等于慢均线快接近的时候,又快速拉升,慢均线就像支撑线。但是如果仅仅就macd的理论,行情在两均线靠近时就已经要反转了,而这往往是错误的判断。所以macd往往要配合均线。我这里采用26日均线来判断趋势,对于看涨函数,只有在均线是向上的时候才会开仓。同理,下面的short判断也是要看均线向下才开仓。


bool CheckForShort()
{
Macd0=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,0);
Macd1=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,1);
Macd2=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,2);

Signal0=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,0);
Signal1=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,1);
Signal2=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,2);

//Ma2=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);

if(Macd0>=Macd1 || Macd1>=Macd2 || Signal0>=Signal1 || Signal1>=Signal2)
{
Print("CheckForShort:macd或者signal不是向下");
return false;
}

highLevel = (Signal0+Signal1+Signal2-Macd0-Macd1-Macd2)/3;

if(highLevel<MACDOpenLevel*Point)//Signal0<=(Macd0+MACDOpenLevel*Point) || Signal1<=(Macd1+MACDOpenLevel*Point) || Signal2<=(Macd2+MACDOpenLevel*Point))
{
Print("CheckForShort:macd不满足开仓必须低于信号足够的数量");
Print("相差",highLevel/Point,"个Point");
return false;
}

//均线变动比较慢
Ma0=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
Ma1=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
//Ma2=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,2);
if(Ma0>Ma1) //|| Ma1>Ma2)
{
Print("CheckForShort:均线向上,没有向下");
return false;
}

if(!CheckForDeathInHour())
{
Print("CheckForShort:有效时间内没有检测到0轴上的死叉");
if(hasConsolidation(0))
{
Print("CheckForShort:检测到盘整行情,现在已经确定走势,可以开仓。");
return true;
}
return false;
}

//if(Macd0<Macd1 && Macd1<Macd2 && Signal0<Signal1 && Signal1<Signal2 &&
// Signal0>(Macd0+MACDOpenLevel*Point) && Signal1>(Macd1+MACDOpenLevel*Point) && Signal2>(Macd2+MACDOpenLevel*Point)
// && Ma0<Ma1)
//{
//检查一小时内有金叉
// if(CheckForDeathInHour())
// return true;
//}

//Print("CheckForShort:not short");
return true;
}


下面就是ontick函数,相当于c语言的main函数,主要是根据多空的判断来开仓和平仓,还有就是移动止损,有点复杂,但是其实也就是一句话的事,就是采用60日均线来作为移动止损点,默认止损是120点,之后取120点和60日均线的大值(要有足够的行情波动空间)。

 //+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnTick(void)
{
//double MacdCurrent,MacdPrevious;
//double SignalCurrent,SignalPrevious;
double MaCurrent;
int cnt,ticket,total;
double stopLost;
//---
// 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 variables
//MacdCurrent=iMACD(NULL,0,26,60,9,PRICE_CLOSE,MODE_MAIN,0);
//MacdPrevious=iMACD(NULL,0,26,60,9,PRICE_CLOSE,MODE_MAIN,1);
//SignalCurrent=iMACD(NULL,0,26,60,9,PRICE_CLOSE,MODE_SIGNAL,0);
//SignalPrevious=iMACD(NULL,0,26,60,9,PRICE_CLOSE,MODE_SIGNAL,1);
MaCurrent=iMA(NULL,0,MATrendPeriod*2,0,MODE_EMA,PRICE_CLOSE,0);
//MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1); //Print("Ask:",Ask," Bid:",Bid," diff point:",(Bid-Ask)/Point); total=OrdersTotal();
if(total<1)
{
//--- no opened orders identified
if(AccountFreeMargin()<(1000*Lots))
{
Print("We have no money. Free Margin = ",AccountFreeMargin());
return;
}
//--- check for long position (BUY) possibility
if(CheckForLong())
{
ticket=OrderSend(Symbol(),OP_BUY,10,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());
}
else
Print("Error opening BUY order : ",GetLastError());
return;
}
//--- check for short position (SELL) possibility
if(CheckForShort()) //&& MaCurrent<MaPrevious)
{
ticket=OrderSend(Symbol(),OP_SELL,10,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());
}
else
Print("Error opening SELL order : ",GetLastError());
}
//--- exit from the "no opened orders" block
return;
}
//--- 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 opened
if(OrderType()==OP_BUY)
{
//--- should it be closed?
if(CheckForShort())
{
//--- close order and exit
if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet))
Print("OrderClose error ",GetLastError());
return;
}
//--- check for trailing stop
if(TrailingStop>0)
{
if(Bid-OrderOpenPrice()>Point*TrailingStop)
{
if(OrderStopLoss()<Bid-Point*TrailingStop)
{
//当前卖价减去TrailingStop作为移动止损线
stopLost = Bid-Point*TrailingStop;
//如果移动止损值高于均线,以均线为止损线。
if(stopLost>MaCurrent)
{
stopLost = MaCurrent;
} //--- modify order and exit
if(!OrderModify(OrderTicket(),OrderOpenPrice(),stopLost,OrderTakeProfit(),0,Green))
Print("OrderModify error ",GetLastError());
return;
}
} if(Bid<OrderOpenPrice())
{ if((OrderOpenPrice()-Bid)>Point*TrailingStop)
{
if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet))
Print("OrderClose error ",GetLastError());
return;
} if((OrderStopLoss()<OrderOpenPrice()-Point*TrailingStop)||(OrderStopLoss()==0))
{
//--- modify order and exit
if(!OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-Point*TrailingStop,OrderTakeProfit(),0,Green))
Print("OrderModify error ",GetLastError());
return;
}
} }
}
else // go to short position
{
//--- should it be closed?
if(CheckForLong())
{
//--- close order and exit
if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet))
Print("OrderClose error ",GetLastError());
return;
}
//--- check for trailing stop
if(TrailingStop>0)
{
if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
{
if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
{ stopLost = Ask+Point*TrailingStop;
if(Ask+Point*TrailingStop<MaCurrent)
{
stopLost = MaCurrent;
} //--- modify order and exit
if(!OrderModify(OrderTicket(),OrderOpenPrice(),stopLost,OrderTakeProfit(),0,Red))
Print("OrderModify error ",GetLastError());
return;
}
} if(OrderOpenPrice()<Ask)
{
if((Ask-OrderOpenPrice())>Point*TrailingStop)
{
if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet))
Print("OrderClose error ",GetLastError());
return;
}
if((OrderStopLoss()>(OrderOpenPrice()+Point*TrailingStop)) || (OrderStopLoss()==0))
{
//--- modify order and exit
if(!OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+Point*TrailingStop,OrderTakeProfit(),0,Red))
Print("OrderModify error ",GetLastError());
}
return;
}
}
}
}
}
//---
}

昨天采用这套策略,抓到一个大行情,模拟盘赚了1万,实盘做的小,500美金的账号,每次下单0.01手,昨天一笔赚了10刀,把我昨天手动亏损的全赚回来了。

当时也是看模拟盘,模拟的不错,一激动入了金,结果发现,外汇还真不是好的发财门道。目前电脑做的比我好多了

最新文章

  1. 微信企业号 获取AccessToken
  2. 制作caffe中的test.txt和val.txt
  3. Atitit. C# java 的api 目录封装结构映射总结
  4. Lua笔记(1)
  5. :parent 匹配含有子元素或者文本的元素
  6. 多项式求ln,求exp,开方,快速幂 学习总结
  7. Owasp Top 10 Security Risks for 2014
  8. jQuery实现公告文字左右滚动的代码。
  9. N种方法妙讲LIS算法
  10. 通过url给action传中文参数乱码解决方案
  11. 二十三种设计模式及其python实现
  12. Java构造器的深入理解
  13. 从零宽断言说起到用python匹配html标签内容
  14. 【Java学习笔记之三十一】详解Java8 lambda表达式
  15. C语言写单链表的创建、释放、追加(即总是在最后的位置增加节点)
  16. eclipse更新time out的问题
  17. # linux文件系统(inode block superblock)
  18. c#文件管理
  19. mybatis批量插入和批量更新
  20. php 阳历转农历优化版

热门文章

  1. Codeforces Round #271 (Div. 2)
  2. 解决魅族USB调试无法被电脑识别的问题(含Mac OS X、Win7)
  3. qt创建android项目后需要加入的参数
  4. HDU 5301 Buildings 建公寓(逻辑,水)
  5. 【转】个人常用iOS第三方库以及XCode插件介绍 -- 不错
  6. [FIX BUG]获取theme中自定义textColor时报的错误
  7. 怎样在 Ubuntu 中修改默认程序
  8. linux命令——磁盘管理cd
  9. 【转】OFBiz安全组
  10. Tableau学习笔记之二