アドバイザープロジェクト - ページ 4

 
Vitaly Muzichenko:

私もそうですが、コードは決して見向きもされない、修正されない、修正されることのない場所にコンパクトにまとめるべきだという結論に、ずいぶん前に達したんです。

ユーザーコードをinludesのあちこちにばらまくと、別の端末にファイルをドラッグ&ドロップ したり、共有する必要があるときに、複数のファイルをドラッグ&ドロップする必要があり、さらなる頭痛の種になります。もちろん、すべての端末にインクルードを転送することもできますが、ある端末で何かを変更したり追加したりすると、すべての端末を新しいものに入れ替えなければなりません。

Expert Advisorとインジケータは非常に小さいので、プログラム本体から距離を置く意味はありません。正しくは、小さいのではなく、単一ファイルです。1万ページあるサイトのように、classやinludesがないとどうにもならない、というわけではありません。しかも、今は構造体があり、コンパクトで100%実行可能なコードを書くには十分なものです。

さあ、始まるぞ...。フォルダのシンボリックリンクについてご存知ですか?http://skesov.ru/sozdanie-simvolnoy-ssyilki-dlya-papki/

私はすべてのライブラリを1つのフォルダに入れており、ターミナルの束には、数十のライブラリがあり、mql*includesフォルダには、この実フォルダへのシンボリックリンクがあります。どこにも引きずる必要はないのです。

また、ストレージも積極的に活用しています。重要なものはすべてそこに置いておけば、5秒で別の端末にダウンロードできますからね。しかし、ライブラリについては、シンボリックリンクの方が便利で、常に完全な同期をとることができます。

Создание символьной ссылки для папки в Windows 8.1, 8, 7, Vista
Создание символьной ссылки для папки в Windows 8.1, 8, 7, Vista
  • 2013.07.24
  • skesov.ru
Доброго времени суток! Сегодня рассмотрим интересную тему под названием «Символьные ссылки». Вариантов использования данного инструмента не так уж много. К примеру, если вы используете часть оперативной памяти как RAM-диск, можно перенести какую-либо игру или её часть (скажем папки с графикой) и создать символьную ссылку. Это значительно...
 
Alexey Navoykov:
MQLフォルダには、シンボリックリンクやジャンクションリンクを使用することをお勧めします。すべての端末が同じフォルダーを見ることになります。

そして、それを誰かと共有する?

 
Vitaly Muzichenko:

誰かと共有する?

まあ、チェックとドライブ、どっちが大事かは自分で決めないとね(笑)。あなたにとって、コーディングの快適さよりも、誰かと共有することの容易さの方が重要ですか?例えば、多くのExpert Advisorで 使われている関数に間違いを見つけた場合、それぞれのExpert Advisorの コードに入り込んでこの関数を書き直さなければなりませんが、プログラマーとしては悩みませんか。

 
私の質問について議論してくれた皆さん、ありがとうございました。
手始めにmqlxのOOPに目を向け、(繰り返し使える)関数を別のファイル(複数)に保存することにしました。そして、コメントを怠らないことです。

そして、Windowsのシンボリックリンクにもう一つ+αを!linuxでは使ったことがあるが、Windowsでは忘れていた。試してみないと...。
 
Alexey Navoykov:

チェックとドライブ、どっちが大事か決めないとね(笑)。あなたにとって、コーディングの快適さよりも、誰かと共有するプロセスのシンプルさが重要なのでしょうか?例えば、多くのExpert Advisorで使われている関数に間違いを見つけたら、それぞれのExpert Advisorのコードに入り込んで、この関数を書き直さなければならない--プログラマーとして悩まないのですか。

このようなケースは1ヶ月ほど前に1度だけあったのですが、そこに市場開放のチェックを加え、これ以外のチェックがあり、使い始めてから初めて飛び出しました。

何か追加する必要があれば、今の番組に追加し、それ以降はそのファイルを次の番組のテンプレートとして使っています。その結果、数年後には、テンプレートがすべて、いや、ほとんどすべてを備えていて、どんな複雑なボットでも30分もあれば書けるようになりました。

4,000行強のファイルですが、実行コード全体は1画面に収まりますが、追加するものだけなら、ごくまれに見る程度です。ループの関数から拒否され、2つだけ使用され、オープン上の1つは、履歴上の第二、およびコードの下部にある構造体のすべてのこの情報を収集します。すべてがとてもシンプルで、近い距離にあります。メインコードはコメント付きです。プロジェクトは 非常に簡単かつ迅速に、損失なく拡張することができます。

 
Alexey Volchanskiy:

TRACE_***とASSERTも見れますか?

まあ...黒い羨望を抱く女性の口説き方マスター クラスの著者には

私のコードでは、対応するシステムマクロが定義されていれば、デバッグバージョンは自動的に有効になります。ただし、有効になっていない場合は、defineによってアサートとトレースを有効にすることも可能です。

#define _FORCETRACE 1
#define _FORCEASSERT 1

この場合、システムの設定に関係なく、デバッグトレースとデバッグアサートが生成されます。

これらのマクロを接続するためのディレクティブがあります。

#include <MyLib\DebugOrRelease\DebugSupport.mqh>

このディレクティブは、必要なファイルや定義をすべてつなぎます。DebugOrReleaseの別フォルダに全部入れてます。ここに添付します。(コードは昔、ほとんど「にわか」で書いたものなので、インターフェースやヒストリークラスのようなきれいなものではありません)。デバッグ版のアサートとトレース自体はAssertDとTraceDのファイルにあり、実際の関数はPerformAssert()とPerformTrace()です。

これらのファイルやマクロの他に、グローバルログファイル(ログファイルへの出力が設定されている場合)を使用します。すでに一度、投稿しましたが、もう一度。ログファイルは、私の「Common」フォルダにあります。

ファイル:
 
Andrey Kisselyov:

良い仕事です、好きです、しかし、私はOOPが好きではなく、OOPなしでやろうとします。 ストリーム分割のあるプロセッサ(例えば4コア8スレッド)は好きではありません。 分割やあらゆる仮想化は、カーネルでのストリーム分割やコードでの機能の仮想化であれ、その実装のための性能低下と機械時間の損失であることは明らかであるべきです。

brevity is the sister of talent(簡潔は才能の姉妹)、その方が響きがいいと思います。

パフォーマンスを下げることよりも、コードの保守性や再利用の方がはるかに重要であることを、私はずいぶん前に学びました。

OOP - しばらくしてからコードに戻って修正するときに、とても役に立ちます。再利用はもちろんのこと。

しかし、常にOOPを使用 する必要性からは程遠いというのは、私も同感です。

例えば、CDataProvider:pulic CDataProviderIクラス - データプロバイダがあり、エキスパートにタイムシリーズ、インディケータ、ターミナル、環境データを提供しています。Expert Advisorは多くのTPを含むことができ、それぞれのTPはデータプロバイダーからタイムシリーズとインジケータへのポインタを受け取ります(各TPはタイムシリーズを作成する必要はありません - 必要なタイムシリーズがすでに存在していればデータプロバイダーはポインタを提供し、まだ作成されていないタイムシリーズのみを作成します)。

データ提供者からインジケータを受け取る必要がある場合 - インジケータ記述構造体に記入し、この構造体を指して提供者にインジケータを要求します。

したがって、データプロバイダー内部の各インジケーターは、その構造を識別し(データプロバイダーは構造の抽象的なベースクラスしか「知らない」)、それに従って、データプロバイダーが作成する準備のできたインジケーターオブジェクトを作成できるようにする必要があります。

しかし、新しい発想の指標を確認するためだけに、これだけのものを作るのは理不尽です。そのため、このような新しい指標は、OOPを一切使わず、すべてが「手作り」なのです。しかし、Expert Advisorに有用なインジケータであれば、OOPを完全にサポートし、データプロバイダー内に作成するなど、「適切に」記述されています。

追伸

ところで、インジケータとデータプロバイダの場合、仮想化継承の利点があります。 インジケータパラメータの基本インターフェースCIndicatorParametersIがあり、このインターフェースの後継が必要なインジケータの実パラメータになります。インジケータを要求する際に、これらのパラメータを宣言し、データプロバイダに抽象インターフェースへのポインタを渡します。このため、データプロバイダー自身は、どのようなインジケータが要求されているのかさえも知りません。そして、この作成されたインジケータだけが、どのようなパラメータが渡されたかを知っており、渡されたオブジェクトから必要なパラメータを取得するのです。

データプロバイダー内部のほぼすべての場所に、パラメータ(またはインジケータ)の単純な基本クラスがあるという仕掛けです。基本インターフェースの最も単純で一般的な機能だけが、データプロバイダーに利用可能です。これにより、(必要な場合の)コードの修正が簡単になり、データ提供者からの指標のコードに「手を加える」誘惑も生まれません。インジケーターを変更する場合、それはインジケーターの内部だけで行われます。データプロバイダーはインジケーターのストレージに過ぎず、できることは最大で新しいインジケーターを作成することです。

 
George Merts:

ちなみに、ネストが2階層以上になると、とても不安になります。 関数にコードを分散させるような書き方は絶対にしないようにしています。

また、ネストレベルが2つある場合でも、それぞれの閉じ括弧の後に、それがどのブロックを閉じているのかコメントを書かなければなりません(例えば、重複するループヘッダなど)。

スタイルに関しては、以下はMT5のヒストリーポジションを 選択するための私のコードです(指定されたマジック、シンボル、指定された日付範囲による)。

履歴クラス自体は、CTradeHistoryI抽象インターフェースの子孫である。

必要な履歴を選択することで、そのコンポーネント(MT5の場合はポジション、MT4の場合は注文)を再計算し、抽象的なインターフェースとして任意のコンポーネントへのインターフェースを取得することができます。

MT4では、これらのインターフェイスを継承したヒストリークラスが用意されており、EAがどこで動作しているかを調べる必要がなく、ヒストリーに関するすべての作業は抽象的なインターフェイスを通じて行われるため、クロスプラットフォームの性質が同時に提供されています。


批判というほどのものでもない。

class CTradePosComponentI: public CMyObject
{
...
}

誰もが理解できる標準的なCObjectがあるのに、なぜCMyObjectという形で車輪を再発明するのでしょうか?

class class CTradeHistoryI: public CMyObject
{
// Расширенный интерфейс
   virtual void Sort(ESortTPCMode stmMode = STM_BY_OPEN_TIME_A) = 0;
}

CObject と CArrayObj の機能がここで明確にコピーされています。なぜ?クイックソートは、標準のデータコンテナに内蔵されています。使ってみてはいかがでしょうか。

class CTradePosComponentI: public CMyObject
{
public:
   void CTradePosComponentI() {    SetMyObjectType(MOT_TRADEPOS_COMPONENT_I); };
   virtual void ~CTradePosComponentI() {};
}

もしクラスがインターフェースを持っているならば、コンストラクタをprotectedセクションに隠した方がよいでしょう。その場合、そのオブジェクトを直接作成することはできません。

空のコンストラクタを定義する?どうだろう。私ならそんなことはしない。デストラクタが必要ないのであれば、触れない方がいいでしょう。

for(iI=0;iI<iHistoryDealsTotal; ++iI)
...

非標準のインクリメントiI、非標準のイテレーション++iI、iHistoryDealsTotal - ループのはるか手前のどこかで定義されています。よりシンプルに

for(int i = 0; i < HistoryDealsTotal();i++)

前バージョンと同じようなスピード感で、よりわかりやすくなりました。

virtual bool               IsTPCInUnloss() const { if(GetTPCStopLoss() <= 0 || GetTPCStopLoss() == EMPTY_VALUE) return(false); if(GetTPCType() == POSITION_TYPE_BUY) { if(GetTPCStopLoss() >= GetTPCOpenPrice()) return(true); } else { if(GetTPCStopLoss() <= GetTPCOpenPrice())return(true); }; return (false); };

プログラマー自身はそのような文章に反対しているようですが、彼ら自身はどこかに書いているのです。そんなくだらないことは誰も調べようとしない。何がそう書かせなかったのか。

virtual bool IsTPCInUnloss() const
{
   if(GetTPCStopLoss() <= 0 || GetTPCStopLoss() == EMPTY_VALUE)
      return(false);
   if(GetTPCType() == POSITION_TYPE_BUY)
   { 
      if(GetTPCStopLoss() >= GetTPCOpenPrice())
         return(true);
   } 
   else
   {
     if(GetTPCStopLoss() <= GetTPCOpenPrice())
        return(true);
   }; 
   return (false);
};

また、中括弧の末尾に「;」がありますが、これは時代遅れで、今はやってはいけないことです。

巨大なSelectメソッドは、巨大なforループで構成されています。

for(iI=0;iI<iHistoryDealsTotal; ++iI)
      {
      ulCurTicket = HistoryDealGetTicket(iI);
      
      if(ulCurTicket == 0)
         return(WRONG_VALUE);
      
      // Получим направление сделки   
      if(HistoryDealGetInteger(ulCurTicket,DEAL_ENTRY,lCurEntry)!=true)
         {
         TRACE_INTEGER("Не удалось получить направление сделки ! Тикет: ",ulCurTicket);
         continue;
         };
      
      // Проверим направление сделки
      if(lCurEntry != DEAL_ENTRY_OUT)
         continue;
      
      // Получим магик сделки
      if(HistoryDealGetInteger(ulCurTicket,DEAL_MAGIC,lCurMagic)!=true)
         {
         TRACE_INTEGER("Не удалось получить магик сделки ! Тикет: ",ulCurTicket);
         continue;
         };
         
      // Проверим магик
      if(ulMagic != NULL && lCurMagic != ulMagic)
         {
         //TRACE_INTEGER("Сделка не подходит ! Имеет неверный магик ! Magic сделки: ",lCurMagic);
         //TRACE_INTEGER("Требуемый Magic : ",ulMagic);
         continue;
         };
      ...
}

明らかに、現在のExpert Advisorとのトランザクションのコンプライアンスのためのすべてのチェックは、例えば、次のように別のメソッドで実装する必要があります。

for(iI=0;iI<iHistoryDealsTotal; ++iI)
{
   if(!CheckDeal(iI))
      continue;
   ...
}

また、一般的にselectは、その中で何が起こっているのかを明確にするために、さらに3~4のメソッドに分割する必要があります。

ジョージ・マーツ
Expert Advisor自体は5行で構成されています。このファイルでは、EAの部品工場自体のオブジェクトを宣言し、インクルージョンも含めています。

ファクトリーは非常に賛否両論あるパターンです。使うのはいいのですが、すべてを工場経由にするのはおすすめしません。

ジョージ・マーツ
また、ネストが2段階ある場合でも、閉じ括弧の後に、どのブロック (例えば重複するループヘッダ)を葬り去るかのコメントを書くことが義務付けられて います。

まあ、だからMQLの醜いやり方で括弧書きにするんだろうけど。そういう書き方をしたのなら

if(OrderSelect())
{
   ...
}

どのブラケットがどのコードブロックを閉じているのか、常に確認することができるのです。

あなたのコードに十数個の警告が見つかったかもしれません。もちろん、コードは完璧ではありませんが、作者の美的センスを感じることができます :))

 
Vasiliy Sokolov:

ちょっと批判的な意見も。

О.そういう議論が好きなんです。だから

誰もが理解できる標準的なCObjectがあるのに、なぜCMyObjectという形で車輪を再発明するのでしょうか?

CObject と CArrayObj の機能は当然ながらここでコピーされる。なぜ?クイックソートは、標準のデータコンテナに内蔵されています。使ってみてください。

CMyObjectは標準のCObjectの後継で、私のコードに登場するリストや配列はすべてCArray(およびその他の標準ライブラリの 配列)の子孫にあたります。標準のarray[]配列はほとんど使いません。

また、リストのソートや操作には、もちろんCObjectの基本的な機能が使われています。

そして、両者の違いは、標準的なCObjectは、「リストまたはソートされた配列のオブジェクト」であることです。CMyObjectは、特定の型を持ち、作成時に与えられた何らかの値を含むCObjectである。このオブジェクトが必要だったのは、オブジェクトの基本的な抽象クラスへの還元が広まったためで、どのオブジェクトが「実際に」指し示しているのかをポインターで理解するためです。CMyObjectのタイプは、まさにその関数SetMyObjectType()によって設定されます。この関数は、CMyObject から派生したオブジェクトのコンストラクタで必ず呼ばれ、オブジェクトが属するクラスの識別子を割り当てなければならない。

また、SetUDCreationValue() - 作成時にユーザー定義の値を設定する - もある。使用頻度が少ない。同じクラスの異なるオブジェクトを区別するために必要です。

クラスのインターフェイス - そのコンストラクタは、保護されたセクションで非表示にする方がよい場合。その場合、そのオブジェクトを直接作成することはできません。

プロテクテッドコンストラクタ ?そうですね、インターフェースには合理的なんでしょうね、知らなかったです。

空のコンストラクタを定義する?どうだろう。そんなことするわけないじゃないですか。デストラクタが必要ない場合は、触れない方がよいでしょう。

それは、「呪われた過去の遺産」です。昔々、かなり大きなプロジェクトを書いたことがありますが、そこでは空のデストラクタを定義しないと、なぜかオブジェクトの削除にかなり時間がかかっていました。だから、それ以来、ずっとその場でやっているんです。一般に、デストラクタも仮想でなければならない。

非標準のインクリメントiI、非標準のイテレーション++iI、iHistoryDealsTotal - ループのはるか手前のどこかで定義されています。もっとシンプルにしたほうがいい。

不一致です。インクリメントは完全に正常で、-i、ただ標準化された表記法で、最初に小さな文字でそのタイプは整数、次に大文字でその名前はIとなります。

そういうシートには反対しているようですが、どこかで書いていますね。そんなくだらないことは誰も分析したがらない。そのように書けなかったのはなぜですか。

この場合、クラスの「見やすさ」と機能の「美しさ」のどちらかを選ぶ必要がありました。私は「視認性」を選びました。美人は苦しんだ。

巨大なSelectメソッドは、巨大なforループで構成されています。

明らかに、現在のExpert Advisorとのトランザクションのコンプライアンスのためのすべてのチェックは、例えば、次のように別のメソッドにする必要があります。

また、一般的にselectはあと3~4メソッドに分割しないと、その中で何が起こっているのかが明確にならない。

私もそう思います。ここでは、原理的に、まさにこのサイクルが「大きくなった」のです、最初はそんなに大きくなかったのですが。

しかし、細かいチェックをプライベート関数に実装するのは、コード上でトレースできないこともあり、必ずしも便利とは言えません。

ファクトリーは非常に賛否両論あるパターンです。使用は問題ありませんが、すべてを工場で行うことはお勧めしません。

今私は覚えていない、エキスパートアドバイザーを構築するためのいくつかのバリエーションがあった。Expert Advisorのパーツ工場」に立ち寄りました。原理的には、もはや純粋な古典的「ファクトリー」パターンではない。元々は「クラシック」なパターンを想定していましたが、現在はむしろExpert Advisorのパーツの「コンストラクタ-・コンセントレータ」になっています。そして、そのパーツを取り外すのも、工場らしくない役割です。しかし、その名前は残った。

だから、MQLの醜いやり方で括弧書きにするわけです。そういう書き方をしたのなら

どのブラケットがどのコードブロックを閉じているのか、常に確認することができるのです。

なぜ「醜い方法」なのか?

ループのヘッダー、インデントされた開始ブラケット、同じインデントでブロック全体、そして最後にインデントされた終了ブラケットです。

何が良いと思いますか?

 
Gregory Kovalenko:

2つの未決済注文で利益を得る必要があります。最後のオープンオーダーをOrderProfit 2と呼び、次のオーダーをOrderProfit1として います。

1次が最初に開かれ、次に2次が開かれるため、ループ内の1次を2)と呼ぶ

どこにエラーがあるのか?

注文を通すだけなんですね。どちらが先でどちらが後かを確認することはどこにもない。

開店時間の チェックを入力する必要があります。そうすれば、先に開いた注文と後から開いた注文を区別することができます。あるいは、同時にオープンできるかもしれません。