mql5言語の特徴、微妙なニュアンスとテクニック - ページ 222 1...215216217218219220221222223224225226227228229...247 新しいコメント Roman 2022.02.21 06:50 #2211 Maxim Kuznetsov #:これは何も新しいことではなく、生まれたときからずっとそうなのです。データが __atomic__ より大きい場合のみ、クリティカルセクションでラップ/プロテクトしてアクセスする必要がある (または、端末 std::thread への mutex が必要)。 なるほど、この挙動は知らなかったので、インポート時に別の処理が行われると思っていました。 グローバルDLLのポインタは、ロードされたMT5プログラムごとに新しくなると思っていました。 なぜメモリ上でエラーがポップアップするのか、ロジックを理解するために汗をかいたことで、理解することができました。 しかし、try(print)メソッドでその理由がわかると、DLLを使った作業全体のアーキテクチャプランが違ってくるのです。 マン、ミューテックスについてはその通りですね、考えてもみませんでした。ご指摘ありがとうございます。 mktr8591 2022.02.21 11:49 #2212 fxsaber #: ZZY サブフィールドやメソッド単位でできないのが残念です。 はい、メソッドにパラメータがない場合は可能ですが。 // Сортировка массива структур и указателей на объекты по методу. #define ArraySortStruct_DefineMethod(METHOD) \ namespace SortOnMethod_##METHOD \ { \ class SORT \ { \ private: \ template <typename T> \ static void Swap( T &Array[], const int i, const int j ) \ { \ const T Temp = Array[i]; \ \ Array[i] = Array[j]; \ Array[j] = Temp; \ \ return; \ } \ \ template <typename T> \ static int Partition( T &Array[], const int Start, const int End ) \ { \ int Marker = Start; \ \ for (int i = Start; i <= End; i++) \ if (Array[i].##METHOD() <= Array[End].##METHOD()) \ { \ SORT::Swap(Array, i, Marker); \ \ Marker++; \ } \ \ return(Marker - 1); \ } \ \ template <typename T> \ static void QuickSort( T &Array[], const int Start, const int End ) \ { \ if (Start < End) \ { \ const int Pivot = Partition(Array, Start, End); \ \ SORT::QuickSort(Array, Start, Pivot - 1); \ SORT::QuickSort(Array, Pivot + 1, End); \ } \ \ return; \ } \ \ public: \ template <typename T> \ static void Sort( T &Array[], int Count = WHOLE_ARRAY, const int Start = 0 ) \ { \ if (Count == WHOLE_ARRAY) \ Count = ::ArraySize(Array); \ \ SORT::QuickSort(Array, Start, Start + Count - 1); \ \ return; \ } \ }; \ } #define ArraySortStructMet(ARRAY, METHOD) SortOnMethod_##METHOD::SORT::Sort(ARRAY) アプリケーションです。 #include <fxsaber\TypeToBytes.mqh> struct MqlRates2: public MqlRates { double Open() {return open;} }; ArraySortStruct_DefineMethod(Open) void OnStart() { MqlRates Rates[]; CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates); // Взяли бары MqlRates2 Rates2[]; _ArrayCopy(Rates2, Rates); Print("\nСортируем Rates2 по open-цене."); ArraySortStructMet(Rates2, Open); ArrayPrint(Rates2); } fxsaber 2022.04.20 16:20 #2213 オーダーの部分的な実行により、ORDER_TIME_SETUP_MSC フィールドが変更されます。 その結果、DEAL_TIME_MSCは、そのオーダーのORDER_TIME_SETUP_MSCより 小さくなることがある。 amrali 2022.04.20 23:46 #2214 カスタム比較関数を使うのはどうでしょう。 //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ typedef double(*TComparer)(MqlRates &a, MqlRates &b); //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class SORT { private: template <typename T> static void Swap(T &Array[], const int i, const int j) { const T Temp = Array[i]; Array[i] = Array[j]; Array[j] = Temp; return; } template <typename T> static int Partition(T &Array[], const int Start, const int End, TComparer Compare) { int Marker = Start; for(int i = Start; i <= End; i++) if(Compare(Array[i], Array[End]) <= 0) { SORT::Swap(Array, i, Marker); Marker++; } return(Marker - 1); } template <typename T> static void QuickSort(T &Array[], const int Start, const int End, TComparer Compare) { if(Start < End) { const int Pivot = Partition(Array, Start, End, Compare); SORT::QuickSort(Array, Start, Pivot - 1, Compare); SORT::QuickSort(Array, Pivot + 1, End, Compare); } return; } public: template <typename T> static void Sort(T &Array[], TComparer Compare, int Count = WHOLE_ARRAY, const int Start = 0) { if(Count == WHOLE_ARRAY) Count = ::ArraySize(Array); SORT::QuickSort(Array, Start, Start + Count - 1, Compare); return; } }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double compare_open(MqlRates &a, MqlRates &b) { return a.open - b.open; } double compare_high(MqlRates &a, MqlRates &b) { return a.high - b.high; } double compare_low(MqlRates &a, MqlRates &b) { return a.low - b.low; } double compare_close(MqlRates &a, MqlRates &b) { return a.close - b.close; } double compare_time(MqlRates &a, MqlRates &b) { return (double)(a.time - b.time); } double compare_tick_volume(MqlRates &a, MqlRates &b) { return (double)(a.tick_volume - b.tick_volume); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnStart() { MqlRates Rates[]; CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates); ArrayPrint(Rates); SORT::Sort(Rates, compare_open); ArrayPrint(Rates); } amrali 2022.04.21 17:00 #2215 fxsaber #:その通りです!ありがとうございました。平らなところでやりすぎました。整理のために、あなたのバリエーションを残しておきます。応用編です。ZZY サブフィールドやメソッドによって、うまくいかないのは残念です。 ここで、私のライブラリから最適化されたQuickSortを、あなたの要件に少し合わせます。 これはスタックのオーバーフローなしに巨大な配列をソートすることができます(制御されていない再帰のため)。 //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ typedef double(*TComparer)(MqlRates &a, MqlRates &b); //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class SORT { private: //+------------------------------------------------------------------+ //| Swaps two variables or two array elements. | //+------------------------------------------------------------------+ template<typename T> static void Swap(T &var1, T &var2) { T temp = var1; var1 = var2; var2 = temp; } //+------------------------------------------------------------------+ //| Insertion Sort | //+------------------------------------------------------------------+ /** * Sort the input array in-place in ascending order. * Insertion sort is the fastest sort algorithm for very small * arrays (<10-20 elements), or when the input is almost sorted. */ template<typename T> static void InsertionSort(T &arr[], int lo, int hi, TComparer Compare) { for(int i = lo + 1; i <= hi; i++) { if(Compare(arr[i], arr[i - 1]) < 0) { T key = arr[i]; int j = i - 1; while(j >= lo && Compare(arr[j], key) > 0) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = key; } } } //+------------------------------------------------------------------+ //| Quick Sort (Optimized) | //+------------------------------------------------------------------+ /** * Sort the input array in-place in ascending order. * Generally, the fastest comparison-based sort algorithm for arrays. * (esp. if large size). * Average time complexity: O(n log n) * Worst-case time complexity: O(n log n) * Stable : no * * Improvements: * * 1. Use insertion sort for small partitions, takes linear time O(n + I) with nearly sorted data. * 2. Choose pivot as the middle element, to avoid the worst case O(n^2) on already-sorted data. * 3. Hoare's parition scheme, which is more efficient than Lomuto's partition scheme * because it does three times fewer swaps on average, and it creates efficient * partitions even when all values are equal (duplicate sort keys). * 4. Sort small partitions using recursion and do tail recursion elimination for large partitions. * This guarantees O(logn) space complexity and avoids stack overflow with huge arrays. */ template<typename T> static void QuickSort(T &arr[], int lo, int hi, TComparer Compare) { // Use a while loop for tail recursion elimination. while(lo < hi) { // Insertion sort is faster for small partitions. if(hi - lo < 16) { InsertionSort(arr, lo, hi, Compare); return; } // Pick pivot as the middle element. int mid = lo + (hi - lo) / 2; T pivot = arr[mid]; // Hoare’s partition scheme. int i = lo; int j = hi; while(i <= j) { while(Compare(arr[i], pivot) < 0) i++; while(Compare(arr[j], pivot) > 0) j--; if(i <= j) { Swap(arr[i], arr[j]); i++; j--; } } // now, a[lo..j] <= a[i..hi] // Sort the small partition first using recursion and do tail recursion elimination for // the large partition. int l_size = j - lo; int r_size = hi - i; if(l_size < r_size) { if(l_size > 0) { QuickSort(arr, lo, j, Compare); } lo = i; } else { if(r_size > 0) { QuickSort(arr, i, hi, Compare); } hi = j; } } } public: template<typename T> static void Sort(T &Array[], TComparer Compare, int Count = WHOLE_ARRAY, const int Start = 0) { if(Count == WHOLE_ARRAY) Count = ::ArraySize(Array); SORT::QuickSort(Array, Start, Start + Count - 1, Compare); } }; //+------------------------------------------------------------------+ //| Compares two fields and returns a value indicating whether one | //| is equal to, less than, or greater than the other. | //+------------------------------------------------------------------+ double compare_open(MqlRates &a, MqlRates &b) { return a.open - b.open; } double compare_high(MqlRates &a, MqlRates &b) { return a.high - b.high; } double compare_low(MqlRates &a, MqlRates &b) { return a.low - b.low; } double compare_close(MqlRates &a, MqlRates &b) { return a.close - b.close; } double compare_time(MqlRates &a, MqlRates &b) { return (double)(a.time - b.time); } double compare_tick_volume(MqlRates &a, MqlRates &b) { return (double)(a.tick_volume - b.tick_volume); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnStart() { MqlRates Rates[]; CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates); ArrayPrint(Rates); SORT::Sort(Rates, compare_open); ArrayPrint(Rates); SORT::Sort(Rates, compare_tick_volume); ArrayPrint(Rates); } Aricoco Arinze 2022.04.21 22:14 #2216 Bodolino #:こんにちは、そして教えてくれてありがとうございますこれが動作すれば完璧です。しかし、.mq5スクリプトに貼り付けて実行すると、残念ながら以下のエラーが発生します。 テンプレート宣言はローカルクラスで許可されていません ArraySortStruct.mq5 87 4 (あなたのコードを少し 変更した後): テンプレート宣言は、グローバル、名前空間またはクラススコープでのみ許可されます ArraySortStruct.mq5 90 4 ) これを修正していただけませんか?あなたにとっては簡単なことでしょうが、私にとっては何から始めればいいのかわかりません :-) Artyom Trishkin 2022.05.16 08:48 #2217 このトピックに関係のないコメントは、「MQL4とMQL5の初心者の質問、アルゴリズムとコードに関するヘルプと議論」に移動しました。 fxsaber 2022.05.19 16:12 #2218 ArrayInsertを使用 する場合、Array_Destination[]が要素を追加するArray_Source[]よりも小さいと、メモリを節約できる。 そのためには、ArrayInsertの前と後の2回、ArraySwapを適用する必要がある。 例えば、これは大きなMqlTickアーカイブなどを扱うときに関係する。 fxsaber 2022.06.06 17:55 #2219 取引、自動取引システム、取引戦略のテストに関するフォーラム mql5言語の特殊性、作業の微妙さとテクニック fxsaber, 2022.02.20 15:00 あなたは正しいです、ありがとうございます!私はまっすぐな場所に過mudryl。私はソートのためにあなたのバリアントを残します。 申請します。 ArraySortStruct_Define(open) ArraySortStruct_Define(high) ArraySortStruct_Define(time) void OnStart() { MqlRates Rates[]; CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates); // Взяли бары Print("\nБары без сортировки - как получили."); ArrayPrint(Rates); Print("\nСортируем по open-цене."); ArraySortStruct(Rates, open); ArrayPrint(Rates); Print("\nСортируем по high-цене."); ArraySortStruct(Rates, high); ArrayPrint(Rates); Print("\nСортируем по времени."); ArraySortStruct(Rates, time); ArrayPrint(Rates); } Partitionメソッドに誤りがありました。修正しました。 // Сортировка массива структур и указателей на объекты по полю. #define ArraySortStruct_Define(FIELD) \ namespace SortOnField_##FIELD \ { \ class SORT \ { \ private: \ template <typename T> \ static void Swap( T &Array[], const int i, const int j ) \ { \ const T Temp = Array[i]; \ \ Array[i] = Array[j]; \ Array[j] = Temp; \ \ return; \ } \ \ template <typename T> \ static int Partition2 ( T &Array[], const int Start, const int End ) \ { \ const T Pivot = Array[End]; \ int i = (Start - 1); \ \ for (int j = Start; j < End; j++) \ if (Array[j].##FIELD < Pivot.##FIELD) \ SORT::Swap(Array, ++i, j); \ \ SORT::Swap(Array, i + 1, End); \ \ return(i + 1); \ } \ \ template <typename T> \ static void QuickSort( T &Array[], const int Start, const int End ) \ { \ if (Start < End) \ { \ const int Pivot = SORT::Partition2(Array, Start, End); \ \ SORT::QuickSort(Array, Start, Pivot - 1); \ SORT::QuickSort(Array, Pivot + 1, End); \ } \ \ return; \ } \ \ public: \ template <typename T> \ static void Sort( T &Array[], int Count = WHOLE_ARRAY, const int Start = 0 ) \ { \ if (Count == WHOLE_ARRAY) \ Count = ::ArraySize(Array); \ \ SORT::QuickSort(Array, Start, Start + Count - 1); \ \ return; \ } \ }; \ } #define ArraySortStruct(ARRAY, FIELD) SortOnField_##FIELD::SORT::Sort(ARRAY) fxsaber 2022.06.19 14:17 #2220 fxsaber #: パーティションメソッドに誤りがありました。修正しました。 数値フィールドがソートに使われる特殊なケース(最も一般的な状況)のために、以前のものより数桁高速な変種を書いた。しかし、2倍のメモリを消費する。これは大きな配列に関係する。 // Сортировка массива структур и указателей на объекты по ЧИСЛОВОМУ полю. #define ArraySortStruct2_Define(FIELD) \ namespace SortOnField_##FIELD \ { \ class SORT2 \ { \ private: \ template <typename T, typename T2> \ static void Sort( T &Array[], const T2& ) \ { \ T2 SortIndex[][2]; \ \ const int Size = ::ArrayResize(SortIndex, ::ArraySize(Array)); \ \ for (int i = Size - 1; i >= 0; i--) \ { \ SortIndex[i][0] = (T2)Array[i].##FIELD; \ SortIndex[i][1] = (T2)i; \ } \ \ ::ArraySort(SortIndex); \ \ T Sort_Array[]; \ \ for (int i = ::ArrayResize(Sort_Array, Size) - 1; i >= 0; i--) \ Sort_Array[i] = Array[(int)SortIndex[i][1]]; \ \ ::ArraySwap(Sort_Array, Array); \ \ return; \ } \ \ public: \ template <typename T> \ static void Sort( T &Array[] ) \ { \ if (::ArraySize(Array)) \ SORT2::Sort(Array, Array[0].##FIELD); \ \ return; \ } \ }; \ } #define ArraySortStruct2(ARRAY, FIELD) SortOnField_##FIELD::SORT2::Sort(ARRAY) アプリケーション(実行時間を測定しながら)。 #include <fxsaber\Benchmark\Benchmark.mqh> // https://www.mql5.com/ru/code/31279 #define _BV2(A) _BV(A, 100) // Алертим все, что исполняется дольше 100 микросекунд. struct STRUCT : public MqlTick { double Num; }; ArraySortStruct_Define(Num) ArraySortStruct2_Define(Num) void OnStart() { STRUCT Array[]; const int Size = ArrayResize(Array, 1 e5); for (int i = Size - 1; i >= 0; i--) Array[i].Num = Size - i; // _BV2(ArraySortStruct(Array, Num)); _BV2(ArraySortStruct2(Array, Num)); } 結果 Alert: Bench_Stack = 0, 100 <= Time[Test9.mq5 129 in OnStart: SortOnField_Num::SORT::Sort(Array)] = 34574468 mcs. Alert: Bench_Stack = 0, 100 <= Time[Test9.mq5 130 in OnStart: SortOnField_Num::SORT2::Sort(Array)] = 10586 mcs. 1...215216217218219220221222223224225226227228229...247 新しいコメント 理由: キャンセル 取引の機会を逃しています。 無料取引アプリ 8千を超えるシグナルをコピー 金融ニュースで金融マーケットを探索 新規登録 ログイン スペースを含まないラテン文字 このメールにパスワードが送信されます エラーが発生しました Googleでログイン WebサイトポリシーおよびMQL5.COM利用規約に同意します。 新規登録 MQL5.com WebサイトへのログインにCookieの使用を許可します。 ログインするには、ブラウザで必要な設定を有効にしてください。 ログイン/パスワードをお忘れですか? Googleでログイン
これは何も新しいことではなく、生まれたときからずっとそうなのです。
データが __atomic__ より大きい場合のみ、クリティカルセクションでラップ/プロテクトしてアクセスする必要がある (または、端末 std::thread への mutex が必要)。
なるほど、この挙動は知らなかったので、インポート時に別の処理が行われると思っていました。
グローバルDLLのポインタは、ロードされたMT5プログラムごとに新しくなると思っていました。
なぜメモリ上でエラーがポップアップするのか、ロジックを理解するために汗をかいたことで、理解することができました。
しかし、try(print)メソッドでその理由がわかると、DLLを使った作業全体のアーキテクチャプランが違ってくるのです。
マン、ミューテックスについてはその通りですね、考えてもみませんでした。ご指摘ありがとうございます。
はい、メソッドにパラメータがない場合は可能ですが。
アプリケーションです。
オーダーの部分的な実行により、ORDER_TIME_SETUP_MSC フィールドが変更されます。
その結果、DEAL_TIME_MSCは、そのオーダーのORDER_TIME_SETUP_MSCより 小さくなることがある。
カスタム比較関数を使うのはどうでしょう。
その通りです!ありがとうございました。平らなところでやりすぎました。整理のために、あなたのバリエーションを残しておきます。
応用編です。
ZZY サブフィールドやメソッドによって、うまくいかないのは残念です。
ここで、私のライブラリから最適化されたQuickSortを、あなたの要件に少し合わせます。
これはスタックのオーバーフローなしに巨大な配列をソートすることができます(制御されていない再帰のため)。
こんにちは、そして教えてくれてありがとうございます
これが動作すれば完璧です。しかし、.mq5スクリプトに貼り付けて実行すると、残念ながら以下のエラーが発生します。
これを修正していただけませんか?あなたにとっては簡単なことでしょうが、私にとっては何から始めればいいのかわかりません :-)
ArrayInsertを使用 する場合、Array_Destination[]が要素を追加するArray_Source[]よりも小さいと、メモリを節約できる。
そのためには、ArrayInsertの前と後の2回、ArraySwapを適用する必要がある。
例えば、これは大きなMqlTickアーカイブなどを扱うときに関係する。
取引、自動取引システム、取引戦略のテストに関するフォーラム
mql5言語の特殊性、作業の微妙さとテクニック
fxsaber, 2022.02.20 15:00
あなたは正しいです、ありがとうございます!私はまっすぐな場所に過mudryl。私はソートのためにあなたのバリアントを残します。
申請します。
Partitionメソッドに誤りがありました。修正しました。
パーティションメソッドに誤りがありました。修正しました。
数値フィールドがソートに使われる特殊なケース(最も一般的な状況)のために、以前のものより数桁高速な変種を書いた。しかし、2倍のメモリを消費する。これは大きな配列に関係する。
アプリケーション(実行時間を測定しながら)。
結果