int CMT5TradeHistory::Select(ulong ulMagic,ECurrencySymbol csSymbol,datetime dtFrom = MIN_DATETIME,datetime dtTill = NEVER_EXPIRES)
{
ASSERT(dtFrom <= dtTill);
// Очистим список ядер позиции
m_aoPosCores.Clear();
// Запросим историю ордеров и сделокif(HistorySelect(dtFrom,dtTill)!=true)
return(WRONG_VALUE);
// Соберем тикеты исторических позиций// Просмотрим все сделки выхода, и выпишем оттуда тикеты позиций.int iHistoryDealsTotal=HistoryDealsTotal();
CArrayLong alHistoryPosIDs;
int iI = WRONG_VALUE;
ulong ulCurTicket = 0;
long lCurPosID = 0;
long lCurMagic = 0;
long lCurEntry = 0;
string strCurSymbol;
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;
};
// Получим символ сделкиif(HistoryDealGetString(ulCurTicket,DEAL_SYMBOL,strCurSymbol)!=true)
{
TRACE_INTEGER("Не удалось получить символ ордера ! Тикет: ",ulCurTicket);
continue;
};
// Проверим символif(csSymbol != CS_UNKNOWN)
if(csSymbol == CS_CURRENT)
{
if(_Symbol2CurrencyEnum(strCurSymbol) != _Symbol2CurrencyEnum(Symbol()))
{
//TRACE2("Symbol выбираемой позиции: ",_Enum2CurrencySymbol(csSymbol));//TRACE2("Выбранный ордер имеет неверный символ: ",strCurSymbol);continue;
};
}
else
{
if(_Symbol2CurrencyEnum(strCurSymbol) != csSymbol)
{
//TRACE2("Symbol выбираемой позиции: ",_Enum2CurrencySymbol(csSymbol));//TRACE2("Выбранный ордер имеет неверный символ ! Символ ордера: ",poiBuffer.GetSymbolString());continue;
};
};
// Получим ID позицииif(HistoryDealGetInteger(ulCurTicket,DEAL_POSITION_ID,lCurPosID)!=true)
{
TRACE_INTEGER("Не удалось получить ID позиции ! Тикет: ",ulCurTicket);
continue;
};
// Проверим ID позицииif(lCurPosID <= NULL)
continue;
if(alHistoryPosIDs.Add(lCurPosID)!=true)
return(WRONG_VALUE);
}; // цикл перебора всех сделок// Здесь ID всех позиций собраны в массиве alHistoryPosIDs, необходимо убрать повторения (в позиции может быть много ордеров)
CArrayLong alUnicalHistoryPosIDs;
if(_DeleteDoubles(GetPointer(alHistoryPosIDs),GetPointer(alUnicalHistoryPosIDs))!=true)
return(WRONG_VALUE);
TRACE_INTEGER("Уникальных ID позиций в истории: ",alUnicalHistoryPosIDs.Total());
// Здесь массив alUnicalHistoryPosIDs заполнен уникальными ID позиций в истории.// Заполним ядра позиции
CMT5HistoryPositionInfoCore* phpiHistPosCore = NULL;
for(iI=0;iI<alUnicalHistoryPosIDs.Total(); ++iI)
{
//TRACE_INTEGER("Выберем позицию: ",iI);// Выберем очередной тикет
lCurPosID = alUnicalHistoryPosIDs.At(iI);
// Позиция является нужной компонентой
ASSERT(phpiHistPosCore == NULL);
phpiHistPosCore = new CMT5HistoryPositionInfoCore;
if(phpiHistPosCore == NULL)
{
m_aoPosCores.Clear();
ASSERT_DSC(false,"Не удалось создать объект CMT5HistoryPositionInfoCore по new");
return(WRONG_VALUE);
};
ASSERT_MYPOINTER(phpiHistPosCore);
if(phpiHistPosCore.SelectByID(lCurPosID)!=true)
{
TRACE("Не удалось создать выбрать позицию ! Возможно, позиция открыта, и еще не полностью в истории.");
TRACE_INTEGER("ID невыбранной позиции: ",lCurPosID);
delete phpiHistPosCore;
phpiHistPosCore = NULL;
continue;
};
ASSERT(phpiHistPosCore.GetTPCOpenTime() > MIN_DATETIME && phpiHistPosCore.GetTPCOpenTime() < phpiHistPosCore.GetTPCCloseTime() && phpiHistPosCore.GetTPCCloseTime() < NEVER_EXPIRES);
// Найдена и выбрана еще одна компонента позицииif(m_aoPosCores.Add(phpiHistPosCore) == false)
{
delete phpiHistPosCore;
m_aoPosCores.Clear();
ASSERT_DSC(false,"Не удалось добавить новый объект в список ядер позиции");
return(WRONG_VALUE);
};
phpiHistPosCore = NULL;
}; // цикл перебора уникальных PosID// TRACE_INTEGER("Ядер в выбранной позиции: ",m_aoPosCores.Total()); return(m_aoPosCores.Total());
};
履歴クラス自体は、抽象的な CTradeHistoryI インターフェースの子孫である。
class CTradeHistoryI: public CMyObject
{
public:
void CTradeHistoryI() { SetMyObjectType(MOT_TRADE_HISTORY_I); };
virtualvoid ~CTradeHistoryI() {};
// Выбор существующей истории. // Указывается магик и символ, по которому выбираются исторические ордера, а также промежуток времени, в котором необходимо искать их.// Если ulMagic = 0 - выбираются все позиции по всем магикам.// Если ECurrencySymbol = CS_UNKNOWN - выбираются все позиции по всем символам// Если ECurrencySymbol = CS_CURRENT - запрашивается функция Symbol(), и выбираются все позиции по этому символу// Возвращает число компонент позиции внутри истории (может быть нулевым если ничего не найдено) или WRONG_VALUE в случае ошибок// NOTE !!! // При выборе - отложенные ордера не учитываются.virtualint Select(ulong ulMagic = 0,ECurrencySymbol csSymbol = CS_CURRENT,datetime dtFrom = MIN_DATETIME,datetime dtTill = NEVER_EXPIRES) = 0;
virtualuint GetTotalComponents() const = 0; // Получение общего числа компонентvirtual CHistoryPosComponentI* GetComponent(uint uiComponentIdx) const = 0;
// Расширенный интерфейсvirtualvoid Sort(ESortTPCMode stmMode = STM_BY_OPEN_TIME_A) = 0;
// Функция ищет внутри истории компоненту с указанным тикетом. // В случае, если ее нет - возвращается false.// Если компонента найдена - возвращается true, и uiComponentIdx устанавливается на индекс компоненты внутри позиции.virtualbool FindComponentByTicket(long lTicket,uint &uiComponentIdx) const = 0;
};
そして、その下にある4つの括弧が何を指しているのかを調べなければならないのです。
ちなみに、ネストが2階層以上になると、とても不安になります。 関数にコードを分散させるような書き方は絶対にしないようにしています。
また、2段階のネストがある場合でも、それぞれの閉じ括弧の後に、どのブロック(例えば、重複するループヘッダ)を葬るのか、必ずコメントを書いてください。
スタイルに関しては、以下はMT5のヒストリーポジションを 選択する私のコードです(指定されたマジシャン、シンボル、指定された日付範囲による)。
履歴クラス自体は、抽象的な CTradeHistoryI インターフェースの子孫である。
必要な履歴を選択することで、そのコンポーネント(MT5の場合はポジション、MT4の場合は注文)を再計算し、抽象的なインターフェースとして任意のコンポーネントへのインターフェースを取得することができます。
MT4では、これらのインターフェイスを継承したヒストリークラスが用意されており、同時にクロスプラットフォームが提供されます。
このスタイルで、常に一定で変化しない関数を書いてはいけない
簡潔に書けば、どうせ誰も見ないし、行数も半分で済む。
これらの関数は変更されないので、なぜ不必要な中括弧をたくさんつけたのでしょうか?それらを取り除くと、すべてが圧縮されます。なぜなら、あなたの例は不合理に見えるからです。あなた自身がコードをぼやかして、それを減らすために松葉杖を考案しているのです。
確かに、あと3行削って、コードを短くすることはできますが、目的は、そのコードを使うことではなく、実は私のものでもなく、短くすることで、そのような機能は、1画面ではなく、5画面に入れることができるのです。それからは、プログラムが見やすくなり、150回もスクロールする必要がなくなりました。そして、ファイルの重量も減少します。
しかし、私はOOPが好きではなく、OOPなしでやっていこうとしています。 スレッドが分割されたプロセッサ(4コア8スレッドなど)も好きではありません。 分割やあらゆる仮想化は、カーネルでのスレッド分割やコードでの機能の仮想化など、その実装のためのパフォーマンスの損失とマシンタイムの損失であることは明らかでなければならないでしょう。
確かに、あと3行削って、コードを短くすることはできますが、目的は、そのコードを使うことではなく、実は私のものでもなく、短くすることで、そのような機能は、1画面ではなく、5画面に入れることができるのです。それからは、プログラムが見やすくなり、150回もスクロールする必要がなくなりました。そして、ファイルの軽量化も実現しました。
敬具
27インチ ワーキングスクリーン
読み返さずに引用します。"常に一定で、 そのスタイルで変化することのない関数を書いては いけない"
プラットフォームがリリースされた時に一度だけ書かれ、今後も変わることのない関数になぜ目を摘むのか。ロットサイズや注文数、代表的なものを取得するために、関数内のコードを変更・編集することはよくあることでしょうか?では、なぜ32インチモニター3画面に引き伸ばすのか?
追伸:添付のコードは、kodobaseから偽造したものです。
カウンタークエスチョン )))このような関数はMyFunc.mqhファイル内にあり、圧縮する意味は全くないと思います。なぜかというと、ディスクに10〜20KB保存するためです。そして、率直に言って、このようなコードストリームは私を病気にします )) 。
カウンタークエスチョン )))MyFunc.mqhにそのような関数がありますが、それを圧縮する意味は少しもないと思います。なぜかというと、ディスクに10〜20KB保存するためです。正直、このコードストリームは気持ち悪いです )) 。
私としては、コードは明確で短く、素早く動作し、どんな状況でもエラーなく動作するものであるべきです。
敬具
カウンタークエスチョン )))MyFunc.mqhにそのような関数がありますが、それを圧縮する意味は少しもないと思います。なぜかというと、ディスクに10〜20KB保存するためです。そして、率直に言って、このようなコードストリームは私をうんざりさせます ))
つまり、1000EA×10Kb=10Mbとカウントして、すでに節約を考える必要があるのです。)
カウンタークエスチョン )))MyFunc.mqhにそのような関数がありますが、それを圧縮する意味は少しもないと思います。なぜかというと、ディスクに10〜20KB保存するためです。そして、率直に言って、このようなコードストリームは私を病気に します )) 。
私もそうですが、ずいぶん前に、コードは誰も見ない場所、修正されない場所、修正されることのない場所にコンパクトにまとめなければならないと思うようになりました。
ユーザーコードをinludesのあちこちにばらまくと、別の端末にファイルをドラッグ&ドロップ したり、共有する必要があるときに、複数のファイルをドラッグ&ドロップする必要があり、さらなる頭痛の種になります。もちろん、すべての端末にインクルードを転送することもできますが、ある端末で何かを変更したり追加したりすると、すべての端末を新しいものに入れ替えなければなりません。
Expert Advisorやインジケータは非常に小さいので、プログラム本体から距離を置く意味はない。正しくは、小さいのではなく、単一ファイルです。1万ページあるサイトのように、クラスやインルードがないとできないわけではありません。しかも、今は構造体があり、コンパクトで100%実行可能なコードを書くにはそれで十分なのです。
ちなみに、ネストが2階層以上になると、とても不安になります。 関数にコードを分散させるような書き方は絶対にしないようにしています。
また、ネストレベルが2つある場合でも、それぞれの閉じ括弧の後に、どのブロック(例えば、重複するループヘッダ)を葬り去るのか、必ずコメントを書いてください。
スタイルについては、MT5のヒストリーポジションを 選択する私のコードです(指定されたマジック、シンボル、指定された日付範囲による)。
履歴クラス自体は、抽象的な CTradeHistoryI インターフェースの子孫である。
必要な履歴を選択することで、そのコンポーネント(MT5の場合はポジション、MT4の場合は注文)を再計算し、抽象的なインターフェースとして任意のコンポーネントへのインターフェースを取得することができます。
MT4では、これらのインターフェイスを継承する対応するヒストリークラスがあり、同時にクロスプラットフォームが提供されています。
良さそうですね、TRACE_***とASSERTも見てみましょうか?
ファイルを 他の端末にドラッグ&ドロップ したり、共有するためには、1つのファイルだけでなく、複数のファイルをドラッグする必要があります。もちろん、すべての端末にインルードを転送することは可能ですが、ある端末で何かを変更・追加した場合、すべての端末で新しいものに置き換える必要があります。