其中,人们可以简单地使用
ObjectCreate(0,"mSmartLinie"+IntegerToString(X),OBJ_HLINE,0,0,0);
其中,一个简单的
X++;
将增加整数X,以便创建
"mSmartLinie0" "mSmartLinie1" "mSmartLinie2" "mSmartLinie3"
和等。
在OOP中,有一些常见的设计模式 用于存储对象和迭代它们。它们被称为容器、集合、集合、地图、矢量(以及其他类似的名称)设计模式,但据说基本的MQL发行版没有提供这些模式。你必须自己编写代码或在代码库中找到它们。
- en.wikibooks.org
我想,我已经明白了--这就是神奇的线条(我希望)。
CSmartLine *ArrayOfSmartLineS[10]; // An array of pointers to CSmartLine object
On ChartEvent
//--- Create another object
CSmartLine*mSmartLine = new CSmartLine();
// Make the new object the owner of the new trend line
mSmartLine.SetName(sparam);
//--- Place the pointer value in an Array
ArrayOfSmartLineS[NoLines]=mSmartLine;
在手册中,只有当他们创建这个类的第一个实例时,才使用 "CSmartLine*mSmartLine = new CSmartLine(); "的形式。
下一次,它只是 "mSmartLine = new CSmartLine();"
这在我的测试框架中是不可能的(编译错误)。???
我写了一个简单的测试框架,功能很差,但测试对象的动态创建。
每当EA检测到一条名为 "beep "的趋势线时--它就会创建一个 "SmartLine "对象,为该线重命名,并从此控制它。
//+------------------------------------------------------------------+
//| Test frame OOP |
//+------------------------------------------------------------------+
class CSmartLine
{
protected:
string iName;
double iRate;
public:
void SetName(string xName)
{
for(int i=0;i<99;i++)
{
iName = "SmartLine_"+IntegerToString(i);
if(ObjectFind(0,iName) < 0) break; // find unused name
}
ObjectSetString(0,xName,OBJPROP_NAME,0,iName); // rename trend line
// --- Get rate
iRate = ObjectGetDouble(0,iName,OBJPROP_PRICE,0);
// signal identification of the line
Sleep(300); PlaySound("ok.wav");
ObjectSetInteger(0,iName,OBJPROP_WIDTH,4); ChartRedraw();
Sleep(300);
ObjectSetInteger(0,iName,OBJPROP_WIDTH,1); ChartRedraw();
//
};
string GetName(void) {return(iName);}
void checkForChange(string xName)
{
if(xName != iName) return;
// Check whether the line has been moved
// get the new position
// --- Get rate
iRate = ObjectGetDouble(0,iName,OBJPROP_PRICE,0);
MessageBox("New rate: "+iName+" = "+DoubleToString(iRate,5));
};
void checkForAction(double iAsk)
{
if(MathAbs(100 * (iRate - iAsk)/iAsk) < 0.005)
{
MessageBox("it's hit me "+iName+
"\n myRate "+DoubleToString(iRate,5)+
"\n actAsk "+DoubleToString(iAsk, 5)+
"\n actDiff "+DoubleToString(100 * (iRate - iAsk)/iAsk,5) );
}
// Calculation whether the price hits the line
// action: beep, buy, sell, close
};
};
//################# E N D - - - C S m a r t L i n e ##########################
//################# B E G I N of E A program ##################################
//--- Declare an array of object pointers of type CSmartLine
CSmartLine *ArrayOfSmartLineS[10]; // An array of pointers to CSmartLine object
int NoLines=0;
//----------------------------------------------------------------------------
void OnInit(void)
{
// --- do I need this?
for(int i=0;i<10;i++)
ArrayOfSmartLineS[i]=NULL;
//--- delete all old trend lines
ObjectsDeleteAll(0,"SmartLine",-1);
}
//+--------------------------------------------------------------------------
void OnChartEvent(const int id,
const long& lparam,
const double& dparam,
const string& sparam)
{
if(id == CHARTEVENT_OBJECT_CLICK ||
id == CHARTEVENT_OBJECT_DRAG ||
id == CHARTEVENT_OBJECT_CHANGE ||
id == CHARTEVENT_OBJECT_CREATE)
{
if(sparam == "beep" || sparam == "buy" || sparam == "sell")
{
//--- Create another object
CSmartLine*mSmartLine = new CSmartLine();
// Make to new object the owner of the new line
mSmartLine.SetName(sparam);
//--- file the pointer value in the array[0]
ArrayOfSmartLineS[NoLines]=mSmartLine;
//--- ask the new object for it's line name
MessageBox("new object: " + ArrayOfSmartLineS[NoLines].GetName());
//
NoLines++;
};
if(StringSubstr(sparam,0,10) == "SmartLine_")
{
for(int i=0;i<10;i++) // Ask all exsisting objects to pick up the change if concerns
{
if(ArrayOfSmartLineS[i] != NULL)
ArrayOfSmartLineS[i].checkForChange(sparam);
}
}
}
}
//----------------------------------------------------------------------------
void OnTick(void)
{
MqlTick last_tick;
SymbolInfoTick(_Symbol,last_tick);
for(int i=0;i<10;i++) // Ask all exsisting objects
{
if(ArrayOfSmartLineS[i] != NULL)
ArrayOfSmartLineS[i].checkForAction(last_tick.ask);
}
}
//+------------------------------------------------------------------+
void OnDeinit(const int xReason)
{
if(xReason == REASON_RECOMPILE ||
xReason == REASON_CHARTCHANGE ||
xReason == REASON_PARAMETERS ||
xReason == REASON_ACCOUNT) return;
//--- We must delete all created dynamic objects
for(int i=0;i<10;i++)
{
//--- We can delete only the objects with pointers of POINTER_DYNAMIC type
if(CheckPointer(ArrayOfSmartLineS[i])==POINTER_DYNAMIC)
{
//--- Notify of deletion
MessageBox("Deleting object "+IntegerToString(i)+" named "+ArrayOfSmartLineS[i].GetName());
//--- Delete an object by its pointer
delete ArrayOfSmartLineS[i];
ArrayOfSmartLineS[i] = NULL;
}
} // Loop i=0;i<10;i++
}
@Marco
我不确定我是否理解你的想法。
你的意思是我应该使用标准的图形对象,写一个继承所有东西的类,并将功能增加到我为我的SmartLines计划的范围吗?
我一直在思考这个想法,我想知道MT5是否允许用户在图表中创建图形对象(通过正常界面)。
除了这个问题,我的SmartLine对象需要在价格变化时被触发,我不知道如何解决这个问题。
你在这方面有什么经验吗?
威尔伯
这只是一个做事的例子。
每当我建立一个GUI或图形用户界面时,我总是在一个循环中建立控制框架。
这意味着控制按钮被简单地创建为B0,B1,B2,B3,B4,B5等,转化为按钮0按钮1按钮2等。
而且我总是使用IntegerToString() 将数字整数添加到对象名称中。
如果你想要触发器,你也可以使用。
if((Ask+Bid)/2>ObjectGetDouble(0,"object name",OBJPROP_PRICE) { // Trigger 1 } else if((Ask+Bid)/2<ObjectGetDouble(0,"object name",OBJPROP_PRICE) { // Trigger 2 }
或者一个变体,因为这只是给你一些想法。
所以你基本上采取一个价格Ask或Bid或Median,并将其与你的Hline目前所处的Double进行比较。
唯一的限制是你自己的想象力。
我不想说你的做法是完全错误的,但你确实这样做了,因为这是结构编程,而不是OOP。最大的区别在于继承和重载的力量。顺便说一下,你不能真正继承真正的图形对象,但你可以把任何东西表示成一个代码对象,并从这个对象中引用一条线或其他东西。这就是通常在任何类中的做法,不管是MFC还是MQL类,它都是一样的。
如果你的行是对象,那么就把它们当作对象。不要在外面处理数组,在类的集合中处理,用指针工作。看一下CWndContainer,对它有一个概念。这个类是一个容器,主要管理CWnd对象的指针数组。再往前走一步,你的结构应该是。
CObject作为每个对象的基础
CPriceTimeObjects作为每个基于价格/时间的对象的基础,比如线,派生自CObject。它控制创建,持有时间和价格,并调用OnCreate(),这可以被下一个继承者使用。它也有一个Tick函数,调用虚拟的OnTick(),然后被继承者重载。
CTrendLine作为趋势线的基础,继承自CPriceTimeObjects并处理OnCreate,它使用ObjectCreate函数 创建最终线。它还应该有一个OnTick()处理程序来对Tick事件做出反应/回应,因为据我所知,它应该是对价格敏感的。
除此之外,你还有一个容器类,它管理着一个指针数组,里面有你想要的所有CTimePriceObject对象,它本身也继承自CTimePriceObject,并将OnTick()传递给它的 "孩子"。容器也有一个处理OnChartEvent()的函数,用于添加或删除线条。它还应该有一个扫描函数来扫描所有现有的对象,以备不时之需,专家是在线条被创建后添加的。此外,它处理来自CTimePrice的重载OnTick(),在那里循环数组,询问其中的每个CTrendLine对象,如果它觉得有责任通过调用每个子对象的Tick函数来做出反应,这是由虚拟OnTick处理的。为什么又是这样?因为CTrendLine也从CTimePrice重载了这个函数,这样这个类也可以被更多的继承者继承,并有更多的函数。
你的代码以后应该是这样的。
CTPContainer容器。
::OnChartEvent(...)
container.ChartEvent(id, lparam, dparam, sparam) //...在每个CTrendLineObject的结果是OnCreate() 和OnDelete()。容器决定要做什么,而不是你的EA。
::OnTick()
container.Tick() // ...导致每个CTrendLine "子 "对象的OnTick()
等等。
这是一个清晰的OOP基础,可以很容易地通过有用的函数来增强,而不需要再去碰任何使用这些类的EA本身。
哇......谢谢你的教诲。
不知为什么,听起来,你已经得到了正确的方法。
我将试着在这个方向上改变我的代码,然后再回来用它。
威尔伯
如果你打算直接进行面向对象的编码,你将永远不会后悔。开始的时候可能比正常的自上而下的方式更难,但你将能够在一个更高的水平上开发,包括更多的力量、更多的可能性、更多的灵活性和更容易兼容未来的变化。
MQL是非常棒的,但是如果没有OOP,你永远不会知道它到底有多棒。
如果你有任何问题,请发表出来,我将尽力帮助你。
这里有一些OOP的东西。
这个程序的想法。
* 我在图表中画了一条趋势线,并将其命名为 "哔"--下次价格越过这条线时,我将得到一个哔声。
* 我画了一条趋势线并命名为 "买入" - 下次价格越过这条线时,我将得到一个多头头寸。
我已经写了一个名为"CSmartLine "的对象,它能够发出哔哔声,买入和卖出,关闭和...。(到目前为止没有咖啡服务)。
在我的EA中,我有三行代码。
void OnTick()
mSmartLinie1.CheckForAction(); // check for crossing prices
void OnChartEvent()
if(id == CHARTEVENT_OBJECT_CLICK ||
id == CHARTEVENT_OBJECT_DRAG ||
id == CHARTEVENT_OBJECT_CHANGE ||
id == CHARTEVENT_OBJECT_CREATE)
if (sparam == "beep" || sparam == "buy" || sparam == "sell" || sparam == "close")
{
mSmartLinie1.CheckForAction(sparam); // activation and tracking changes
return;
};
到目前为止效果不错。
现在 . . . .我想在图表中绘制任意数量的智能趋势线。
假设该对象改变了线的名称(如改为 "SmartLine_x"),以显示该线是在它的控制之下。
每当EA检测到一条新线,它应该创建一个新的 "CSmartLine "类对象。
代码可以是
OnChartEvent()
if (sparam = "beep")
mSmartLine2 = new CSmartLine;
OnTick()
if(mSmartLine2 != Null)
mSmartLine2.CheckForAction();
但如何.... hmmm ....
也许 "mSmartLine "应该是一个指针数组? 如果是这样,哪种类型?
手册在他点显示了一个我无法理解的例子。
当趋势线消失时(例如,因为用户从图表中删除了它).
代码应该是 . .
delete mSmartLine2;
mSmartLine2=NULL;
因为是对象本身识别了线的消失,所以应该是对象自己删除,而不是要求EA删除它。
WIllbur