ここで,単純に
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++
}
マルコ
あなたの考えを理解できたかどうか、自信がありません。
つまり、標準的なグラフィック・オブジェクトを使用して、そこからあらゆるものを継承し、私の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と比較するわけです。
唯一の限界は自分の想像力です。
Marcoさん、あなたはまだEAコードの中にいるんですよね。そうなんですか?
これは私が言っていることではありません。
このアイデアは、与えられたgraficオブジェクトに機能を追加するために、オリジナルのgraficオブジェクトを継承した独自のオブジェクトを書き、「買い」と「売り」の機能を増やしたものです。
このようにすると、私のSmartLineオブジェクトは、MT5のメニューに、トレンドライン、矢印、テキストオブジェクト、その他すべてのものの横に表示されるはずです。
他のグラフィック・オブジェクトのようにマウスで選んで、チャートに追加することができます。
MT5で表示できるようになったら、残りの問題、つまり価格が変化したときにターミナル・プログラムからどのようにオブジェクトをトリガーさせるかを議論しなければなりません。
既存のグラフィックオブジェクトは、価格変動に反応することはできません(私の知る限り)。
ウィルバー
これは構造体プログラミングであり、OOPではないので、完全に間違っているとは言えません。大きな違いは、継承とオーバーロードの力です。ところで、実際のグラフィカル・オブジェクトを継承することはできませんが、あらゆるものをコード・オブジェクトとして表現し、そのオブジェクトから線などを参照することは可能です。これはMFCやMQLのクラスでも同じです。
もし行がオブジェクトなら、そのように扱います。外では配列を扱わず、クラスコレクションの中でポインターを扱います。CWndContainerを見て、そのイメージを掴んでください。このクラスは、主にCWndオブジェクトのポインタ配列を管理するコンテナです。もう一歩進んで、あなたの構造はこうなっているはずです。
すべてのオブジェクトのベースとなるCObject
CPriceTimeObjectsは、価格や時間に基づくオブジェクトのベースとなるもので、CObjectから派生したものです。このオブジェクトは作成をコントロールし、時間と価格を保持し、次の継承者が使用できるOnCreate()を呼び出します。また、Tick関数も持っており、仮想のOnTick()を呼び出し、それを継承者がオーバーロードしています。
トレンドラインのベースとなるCTrendLineは、CPriceTimeObjectsを継承し、ObjectCreate関数を使って 最終ラインを作成するOnCreateを扱います。また、OnTick()ハンドラを持って、Tickイベントに反応するようにします。
これに加えて、CTimePriceObjectオブジェクトを保持するポインタ配列を管理するコンテナ・クラスがあり、これもCTimePriceObjectを継承してOnTick()をその「子」たちに渡している。コンテナにはOnChartEvent()を処理する関数もあり、線を追加したり削除したりする。また、行が作成された後にエキスパートが追加された場合、既存のオブジェクトをすべてスキャンするスキャン関数も持っている必要があります。さらに、CTimePriceからオーバーロードされたOnTick()を処理し、そこの配列をループし、その中のすべてのCTrendLineオブジェクトに、仮想OnTickによって処理されるすべての子オブジェクトのTick関数を呼び出して反応する責任を感じるかどうかを尋ねます。なぜまたこのようなことをするのでしょうか?なぜなら、CTrendLineはこの関数をCTimePriceからもオーバーロードしており、このクラスはさらなる関数を持つ継承者に継承されることが可能だからです。
あなたのコードは後でこのようになるはずです。
CTPContainerコンテナ。
::OnChartEvent(...)
container.ChartEvent(id, lparam, dparam, sparam) //... 結果として、各CTrendLineObjectでOnCreate(), OnDelete()が発生します。何をするかはEAではなく、コンテナが決定します。
::OnTick()
container.Tick() // ... 結果として、各CTrendLine「子」オブジェクトでOnTick()が発生します。
といった具合になります。
このように、OOPの基本は明確であり、これらのクラスを使用するEA自体に再び触れることなく、便利な機能によって簡単に拡張することができます。
うわー......教えをありがとうございます。
なんとなくですが、あなたが正しいアプローチをしているように聞こえます。
私はそれで戻ってくる前に、この方向に私のコードを変更しようとします。
Willbur
もし、あなたがすぐにオブジェクト指向のコードを書こうとするならば、決して後悔することはないでしょう。最初は通常のトップダウン方式より難しいかもしれませんが、より多くのパワー、より多くの可能性、より多くの柔軟性、将来の変化への容易な対応など、より高いレベルで開発できるようになります。
MQLは素晴らしいものですが、OOPなしでは、その真価を発揮することはできないでしょう。
もし、何か質問があれば、投稿してください。
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索
ここで、いくつかのOOPが登場します。
プログラムのアイデア
* 私はチャートにトレンドラインを引き、それを "ビープ "と名付けます。
* 私はトレンドラインを描き、それを "買い "と名付ける - 価格が次にこのラインを横切ったとき、私はロングポジションを取得します。
すでに "CSmartLine "という名前のオブジェクトを 書き、ビープ音と売買と決済を行うことができるようにした。(コーヒーサービスは今のところありません)。
私のEAで私はコードの3行を持っています。
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();
しかし、どのように......うーん......。
多分 "mSmartLine "はポインタの配列でなければなりませんか? もしそうなら、どのタイプですか?
マニュアルには、私が理解できない例が示されています。
トレンドラインが消えたとき(例えば、ユーザーがチャートからそれを削除したため).
コードは... ...でなければなりません。
delete mSmartLine2;
mSmartLine2=NULL;
ラインの消滅を認識するのはオブジェクト自身なので、EAに削除を依頼するのではなく、オブジェクトが自身を削除する必要があります。
WIllbur