简介
本文详述了在实时模式中进行赌博建模的简单机制。那什么是赌博呢?金融赌博 - 预测某证券的未来走势(上涨或下跌)并在预测正确时获利。(由 MetaQuotes Software Corp. 自 Russian Wikipedia 翻译为英语)
实际上,我们在赌博中只关注一件事:证券是上涨还是下跌?而走势中的交易量对我们并不重要。
如果在较小的时间范围内以游戏的形式进行赌博,我们可以培养“市场直觉”。我们可以学习“预见”某个货币对要上涨还是下跌。这就是本文要描述的内容。
概念
人们普遍认为,了解技术分析、基本面分析、资金管理规则等,对交易者非常重要。毋庸置疑,所有这些都很重要。但还有所谓的“市场直觉” - 即当交易者观察一张没有任何指标的空白图表时,能够大约看出证券移动的方向。当然,这种预测并非始终准确,但每种交易方法都可能发生错误。这种“预见”市场的能力仍然非常有用,尤其在需要快速评估市场状况的时候。
“市场直觉”通常是大量经验和无数试验的结果。这种“试验”的代价经常达到成千上万美元。
但我认为,存在以更少的时间和金钱来培养这种直觉的方法。方法之一是制作一个游戏,其意义就是预测一个证券的走势。如果该游戏跟实时交易条件关联,则更佳。也可以跟真实交易联系起来。
毫无疑问,人的能力是可以练习和开发的。我们可以学习绘画、唱歌和演奏不同的乐器。我相信人同样可以学习“预见”市场。我们可以玩电脑游戏。同样,也可以玩“预测方向”的游戏。但我们在这里需要了解的是开始做什么和如何培养这项能力。首先,我们需要游戏本身。
设定任务
那我们需要什么呢?需要可以实时模式在真实图表上进行的游戏。游戏的规则应该非常简单和容易操作。且游戏应该使注意力尽可能多的保持在市场上而非执行的操作。此外,游戏不应该从可能的真实交易中分散很多注意力。
赌博似乎满足以上所有要求。但在现实生活中,赌博并不很方便。没有很多经纪公司提供这种机会。即使你好不容易找到一个这样的公司,可能也会面临诸多不便。例如,模拟账户可能会分散你真实交易的注意力。对于真实帐户,这个游戏的风险过大。通常,赌博的持续时间不能少于一个小时。
可见,这种变体未能完全符合我们的任务。最终,我们需要为该游戏编写单独的程序 - 没有这种限制的程序。MQL4 完美的符合我们的目的。
实施
我们从简单的问题开始:它看起来应该是什么样子?显然,用户应该从给出的变体中二选一 - 上涨或下跌(预测某证券的未来走势)。如果猜测正确,程序加一分;如果错误则减一分。
进行选择最好通过对象实现 - SYMBOL_ARROWDOWN 和 SYMBOL_ARROWUP。用户可以在图表上放置必要的箭头。但绘制和写入签名会花费大量时间和注意力。所以该变体并不适合。
另一个变体是在新蜡烛图开始处自动放置两个箭头。用户应删除其中一个箭头,留下的箭头指示其猜测。然后,Expert Advisor 应该在新蜡烛图开始处检测预测是否正确。最后计算总分、正确和错误预测的数量。为此,要使用外部文件进行录入。
这听起来并不难。实施起来也很容易。
//+------------------------------------------------------------------+ //| trener.mq4 | //| Copyright © 2008, FXRaider | //| | //+------------------------------------------------------------------+ #property copyright "Copyright © 2008, FXRaider" //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ extern int gap=5; int init() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { //------------------------------ string solution="none"; int point, point_neg, point_pos; //------------------------------ //+---------------------------------------------------------------+ //| "up" choice searching | if( ObjectGet("up", OBJPROP_PRICE1)==Open[1]+gap*Point &&iBarShift(NULL,0,ObjectGet("up",OBJPROP_TIME1))==1 &&ObjectFind("down") != 0 &&ObjectFind("up") == 0 ) { solution="up"; } //| "up" choice searching | //+---------------------------------------------------------------+ //+---------------------------------------------------------------+ //| "down" choice searching | if( ObjectGet("down", OBJPROP_PRICE1)==Open[1]-gap*Point &&iBarShift(NULL,0,ObjectGet("down",OBJPROP_TIME1))==1 &&ObjectFind("up") != 0 &&ObjectFind("down") == 0 ) { solution="down"; } //| "down" choice searching | //+---------------------------------------------------------------+ //+---------------------------------------------------------------+ //| counting points at a positive answer | if((solution=="up"&&Open[1]<Close[1]) ||(solution=="down"&&Open[1]>Close[1])) { point=1; point_pos=1; point_neg=0; } //| counting points at a positive answer | //+---------------------------------------------------------------+ //+---------------------------------------------------------------+ //| counting points at a negative answer | if((solution=="up"&&Open[1]>Close[1]) ||(solution=="down"&&Open[1]<Close[1])) { point=-1; point_pos=0; point_neg=1; } //| counting points at a negative answer | //+---------------------------------------------------------------+ //+----------------------------------------------------------------------------------+ //| working with an external file | int handle; double points, //total score points_pos, //score of positive answers points_neg; //score of negative answers handle=FileOpen("trener_"+Symbol()+"_"+Period()+".csv", FILE_CSV|FILE_WRITE|FILE_READ,";"); if(handle>0) //if there is a file, read it { points=NormalizeDouble(StrToDouble(FileReadString(handle)),Digits); points_pos=NormalizeDouble(StrToDouble(FileReadString(handle)),Digits); points_neg=NormalizeDouble(StrToDouble(FileReadString(handle)),Digits); FileClose(handle); } if(solution!="none") //if a choice is made { handle=FileOpen("trener_"+Symbol()+"_"+Period()+".csv", FILE_CSV|FILE_WRITE|FILE_READ,";"); FileWrite(handle ,points+point); //write the total score FileWrite(handle ,points_pos+point_pos); //write the score of positive answers FileWrite(handle ,points_neg+point_neg); //write the score of negative answers FileClose(handle); } //| working with an external file | //+----------------------------------------------------------------------------------+ //+------------------------------------------------------------------------------------+ //| working with objects | if(iBarShift(NULL,0,ObjectGet("down",OBJPROP_TIME1))>0 ||ObjectGet("down",OBJPROP_PRICE1)!=Open[0]-gap*Point) { ObjectDelete("down"); } if(iBarShift(NULL,0,ObjectGet("up",OBJPROP_TIME1))>0 ||ObjectGet("up",OBJPROP_PRICE1)!=Open[0]+gap*Point) { ObjectDelete("up"); } if(ObjectFind("down") != 0&&ObjectFind("up") != 0) //if no object { ObjectCreate("down", OBJ_ARROW, 0, Time[0], Open[0]-gap*Point); //draw a down arrow ObjectSet("down", OBJPROP_STYLE, STYLE_DOT); ObjectSet("down", OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN); ObjectSet("down", OBJPROP_COLOR, Red); ObjectCreate("up", OBJ_ARROW, 0, Time[0], Open[0]+gap*Point); //draw an up arrow ObjectSet("up", OBJPROP_STYLE, STYLE_DOT); ObjectSet("up", OBJPROP_ARROWCODE, SYMBOL_ARROWUP); ObjectSet("up", OBJPROP_COLOR, Blue); } //| working with objects | //+------------------------------------------------------------------------------------+ Comment("Score: ", points," (",points_pos,"/",points_neg, //show the score ") | Time: ", Hour(),":", Minute(),":", Seconds());//show time (for convenience) //---- return(0); } //+------------------------------------------------------------------+
代码中包含注释。
在添加至图表后,我们得到如下结果:
在最后的柱上可以看到两个箭头 - 向上和向下。在左上角可以看到游戏的分数和最后一次价格变动的终端时间。分数以三个数字显示:第一个是总分,第二个(括号中第一个)是正面答案(正确的预测)的数量,第三个(括号中第二个)是负面答案(错误的预测)的数量。为了操作方便,时间以全屏模式显示(F11)。
为了“玩”游戏,应该使用双击(默认)选择“不必要”的箭头并按“Delete”键(进行删除)。余下的箭头指示我们的预测。
然后等待下一个柱的开始。如果预测正确,“Score”的形式如下:"Score:1(1/0)".如果预测错误,“Score”呈现如下:"Score:-1(0/1)".如果收盘价等于开盘价,分数不变。在示例中,预测是错误的:
改进
我们的任务已经完成。但存在一个不足之处:你可以在整个蜡烛图上进行选择,包含最后几秒钟。这似乎不公平。如果在前 30 秒内进行选择,会好很多。为此,我们引入外部 int 变量 - “time_limit”。它的值等于秒数,应在该时间内作出选择。如果用户未能在该时间内做出选择,箭头将从图表删除,并在下一个蜡烛图上显示。
更改将显示在“working with objects”部分(解释请见注释)。下面是代码:
//+------------------------------------------------------------------+ //| trener.mq4 | //| Copyright © 2008, FXRaider | //| | //+------------------------------------------------------------------+ #property copyright "Copyright © 2008, FXRaider" //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ extern int gap=5; extern int time_limit=30; int init() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { //------------------------------ string solution="none"; int point, point_neg, point_pos; //------------------------------ //+---------------------------------------------------------------+ //| "up" choice searching | if( ObjectGet("up", OBJPROP_PRICE1)==Open[1]+gap*Point &&iBarShift(NULL,0,ObjectGet("up",OBJPROP_TIME1))==1 &&ObjectFind("down") != 0 &&ObjectFind("up") == 0 ) { solution="up"; } //| "up" choice searching | //+---------------------------------------------------------------+ //+---------------------------------------------------------------+ //| "down" choice searching | if( ObjectGet("down", OBJPROP_PRICE1)==Open[1]-gap*Point &&iBarShift(NULL,0,ObjectGet("down",OBJPROP_TIME1))==1 &&ObjectFind("up") != 0 &&ObjectFind("down") == 0 ) { solution="down"; } //| "down" choice searching | //+---------------------------------------------------------------+ //+---------------------------------------------------------------+ //| counting points at a positive answer | if((solution=="up"&&Open[1]<Close[1]) ||(solution=="down"&&Open[1]>Close[1])) { point=1; point_pos=1; point_neg=0; } //| counting points at a positive answer | //+---------------------------------------------------------------+ //+---------------------------------------------------------------+ //| counting points at a negative answer | if((solution=="up"&&Open[1]>Close[1]) ||(solution=="down"&&Open[1]<Close[1])) { point=-1; point_pos=0; point_neg=1; } //| counting points at a negative answer | //+---------------------------------------------------------------+ //+----------------------------------------------------------------------------------+ //| working with an external file | int handle; double points, //total score points_pos, //score of positive answers points_neg; //score of negative answers handle=FileOpen("trener_"+Symbol()+"_"+Period()+".csv", FILE_CSV|FILE_WRITE|FILE_READ,";"); if(handle>0) //if there is a file, read it { points=NormalizeDouble(StrToDouble(FileReadString(handle)),Digits); points_pos=NormalizeDouble(StrToDouble(FileReadString(handle)),Digits); points_neg=NormalizeDouble(StrToDouble(FileReadString(handle)),Digits); FileClose(handle); } if(solution!="none") //if a choice is made { handle=FileOpen("trener_"+Symbol()+"_"+Period()+".csv", FILE_CSV|FILE_WRITE|FILE_READ,";"); FileWrite(handle ,points+point); //write the total score FileWrite(handle ,points_pos+point_pos); //write the score of positive answers FileWrite(handle ,points_neg+point_neg); //write the score of negative answers FileClose(handle); } //| working with an external file | //+----------------------------------------------------------------------------------+ //+------------------------------------------------------------------------------------+ //| working with objects | if(iBarShift(NULL,0,ObjectGet("down",OBJPROP_TIME1))>0 ||ObjectGet("down",OBJPROP_PRICE1)!=Open[0]-gap*Point) { ObjectDelete("down"); } if(iBarShift(NULL,0,ObjectGet("up",OBJPROP_TIME1))>0 ||ObjectGet("up",OBJPROP_PRICE1)!=Open[0]+gap*Point) { ObjectDelete("up"); } int sec_lim; if(!time_limit) { sec_lim=0; } else { sec_lim=TimeCurrent()-time_limit; } if(sec_lim>ObjectGet("up",OBJPROP_TIME1) &&sec_lim>ObjectGet("down",OBJPROP_TIME1) &&ObjectFind("down") == 0&&ObjectFind("up") == 0 &&iBarShift(NULL,0,ObjectGet("down",OBJPROP_TIME1))==0 &&iBarShift(NULL,0,ObjectGet("up",OBJPROP_TIME1))==0) { ObjectDelete("up"); ObjectDelete("down"); } if((ObjectFind("down") != 0&&ObjectFind("up") != 0) //if no objects &&sec_lim<Time[0]) { ObjectCreate("down", OBJ_ARROW, 0, Time[0], Open[0]-gap*Point); //draw a down arrow ObjectSet("down", OBJPROP_STYLE, STYLE_DOT); ObjectSet("down", OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN); ObjectSet("down", OBJPROP_COLOR, Red); ObjectCreate("up", OBJ_ARROW, 0, Time[0], Open[0]+gap*Point); //draw an up arrow ObjectSet("up", OBJPROP_STYLE, STYLE_DOT); ObjectSet("up", OBJPROP_ARROWCODE, SYMBOL_ARROWUP); ObjectSet("up", OBJPROP_COLOR, Blue); } //| working with objects | //+------------------------------------------------------------------------------------+ Comment("Score: ", points," (",points_pos,"/",points_neg, //show the score ") | Time: ", Hour(),":", Minute(),":", Seconds());//Show time (for convenience) //---- return(0); } //+------------------------------------------------------------------+
我们在输入参数中有两个可变变量:
“gap”参数指示点数 - 箭头和蜡烛图开盘价的距离。“time_limit”变量指示秒数,在该时间内用户应做出选择。如果值为“0”,则没有时间限制,即可以在整个蜡烛图上做出选择。
总结
现在,我们已经使用 MQL4 语言对金融赌博进行了简单的建模。该游戏可以极大的培养你“预见”市场的能力,以及帮助学习证券走势的很多规律。该版本的实现方式可以使交易者的注意力最大化的集中在价格图表上。交易者执行的操作需要的时间最少且容易理解。
我想分享自己的游戏结果。我在连续 5-10 个蜡烛图上做出正确预测(在五分钟的图表上)。
利用该游戏,交易者可以学习回答最重要的问题之一:证券将朝什么方向移动?仍有很多其他重要的问题,例如获利、弥补损失、选择打开的交易量等等。只有了解了如何回答所有这些问题,才能获得稳定的交易结果。
还有一个重要的问题是交易者的休息时间。该游戏比当前娱乐市场上的任何其他游戏更加有用。