受注サイクルの整理 - ページ 9

 
fxsaber:

変更あり

現在はアラートなし。

答えは明白で、もしTicket == PrevTicketであれば --->WRONG_VALUEを 返します。

もし、関数が0より小さい値を返したら、再度呼び出す必要があります。

 
Artyom Trishkin:

答えは明白で、もしTicket == PrevTicketであれば --->WRONG_VALUEを 返します。

というわけで、これは、近傍のチケットの等価性という形でわかりやすく説明した問題の特殊なケースの解法です。

実は問題は同じで、ループ中のインデックスの揺れなのです。そのため、あるチケットがスキップされたり、あるチケットが繰り返されたりするなどの事態が発生することがあります。

IsChangeに代わるものは見つかっていません。

 
fxsaber:

つまり、これは問題の特殊なケースに対する解決策で、わかりやすくするために隣りのチケットの等価性という形で表現したのです。

問題は、実はすべて同じで、サイクル中にインデックスを揺るがすことです。そのため、あるチケットがスキップされたり、あるチケットが繰り返されたりするなどの事態が発生することがあります。

IsChangeに代わるものは見つかっていません。

タイマーでリストを作成し、それをもとに作業を行います。

 
Artyom Trishkin:

タイマーでリストを作成し、作業する。

コードでより良くする。

 
fxsaber:

コードでより良くする。

これはコードで示すのは非常に難しく、相互に関連するクラスがライブラリ全体に存在します。

アイデアは以下の通りです。口座上のすべての注文とポジションを渡し、タイマー内のCArrayObjリストを埋めます。実際の情報を一度に入手できるよう、常にアップデートしています。

ポジションのクローズや オーダーの削除が必要な場合、このリストを取得し、クローズ(変更)機能に必要なオーダーオブジェクトとそのチケットを選択します。このオーダーオブジェクトが物理的に存在しない場合(これらのアクションの間に閉じられたか削除された)、このオブジェクトはすでに閉じられているので、単にリストの次のオブジェクトに移動し、リストは次のタイマーの反復で更新されます。最初に思い浮かぶ問題は、リストに載っている行動の時間経過とともに取引環境が変化すると、リストが無関係になることです。しかし、私が思うに、リストから注文が物理的に欠落しても、あまり気にならないはずです。このリストは取引環境のようにシャッフルされないので、スキップは不可能です。

まだコードに実装していないので、今のところ こう考えています。私はちょうど実装の準備をしているところですが、最初は他のクラスを完成させる必要があります(Featuresブランチで関数の代入について質問しました)。実装を始めると、考えられる問題がそこに見えてくるので、それをどう解決していくかを決め、修正していきます。

 
Artyom Trishkin:

答えは明白で、もしTicket == PrevTicketであれば --->WRONG_VALUEを 返します。

もし、関数が0より小さい値を返したら、もう一度呼び出す必要があります。

全く何もしなくていいんです。バカみたいな理屈をこねていればいいんです。

6件のご注文をいただきました

  • 0 チケット 100
  • 1枚 101
  • 2券種 102
  • 3券種 103
  • 4券種 104
  • 5券種 105

例えば、改造のための注文を調べ始めます。

5枚のチケット105を選び、修正するかどうかを確認し、修正する。

この時、私たちの汚れた手で、オーダー2チケット102を削除し、リストを変更しました。チケット105のオーダーは、リストの4番目、4になりました。 そして、再び修正用に選択されています。しかし、私たちはチェックせずに仕事をするわけではありません...。修正すべきかどうか確認しました。そんなことはない...だからなんだ?オーダーが選び直されたことで、誰が傷ついたのか?

 
Artyom Trishkin:

これはコードで示すのは非常に難しく、相互に関連するクラスがライブラリ全体に存在します。

アイデアは以下の通りです。口座上のすべての注文とポジションを渡し、タイマー内のCArrayObjリストを埋めます。実際の情報を一度に入手できるよう、常にアップデートしています。

ポジションのクローズや オーダーの削除が必要な場合、このリストを取得し、クローズ(変更)機能に必要なオーダーオブジェクトとそのチケットを選択します。もし、このオーダーオブジェクトが物理的に存在しない(これらのアクションの間に閉じられるか削除される)場合、このオブジェクトはすでに閉じられているので、単にリストの次のオブジェクトに移動し、リストは次のタイマーの反復で更新されることになる。最初に思い浮かぶ問題は、リストに載っている行動の時間経過とともに取引環境が変化すると、リストが無関係になることです。しかし、私が思うに、リストから注文が物理的に欠落しても、あまり気にならないはずです。このリストは取引環境のようにシャッフルされないので、スキップは不可能です。

まだコードに実装していないので、今のところ こう考えています。私はちょうど実装の準備をしているところですが、最初は他のクラスを完成させる必要があります(Featuresブランチで関数の代入について質問しました)。実装を始めると、考えられる問題がそこに見えてくるので、それをどう解決していくかを決め、修正していきます。

以下はその実装です。

トレーディング、自動売買システム、トレーディング戦略のテストに関するフォーラム

オーダーループの整理

fxsaber さん 2017.09.11 20:29

// Редкий, но правильный костяк модификации ордеров
for (int i = OrdersTotal() - 1; i >= 0; i--)
  if (OrderSelect(i, SELECT_BY_POS))
    if (OrderModify(OrderTicket(), Price, SL, TP, OrderExpiration()))     
    {
      i = OrdersTotal(); // Хотя бы так
      
      // А лучше так
//      OnTick(); break; // вместо строки выше лучше делать такой вызов (переполнения стека от рекурсивных вызовов быть не должно)
    }


取引注文の 送信後、取引環境が変化するため、取引サーバーの応答後、直ちにTSの全取引ロジックを一から実行することが望ましいです。

ただ、まだIsChangeが必要です。タイマーは全くオプションではありません。Sleep(1) でも全体像が台無しになる。

 
Alexey Viktorov:

絶対に何もする必要はありません。馬鹿の一つ覚えのような顔で理屈をこねて歩けばいいのです。

Takiさん、はい、注文のクローズ/アクティベーションにチェックが入っていれば問題ありません。
もし、独自のティックの配列があれば、注文は失敗することになります。

ps. 別のケースを紹介しましょう。保留中の注文が実際の注文を止めるように設定されている場合(ロールオーバーのため)、ストップが発動されると、保留中の注文は不定時間、開始が遅れる可能性があるのです。つまり、一方の注文はマーケットでトリガーされ、もう一方は一定のティック数だけぶら下がる......というものだ。

 
fxsaber:

以下はその実装です。

ただ、まだIsChangeが必要です。タイマーは全くオプションではありません。Sleep(1) でも全体像が台無しになる。

IsChange()はタイマーにきっちり実装されています(テスト版はまだ完成していません)。

//+------------------------------------------------------------------+
//| Обновляет список ордеров                                         |
//+------------------------------------------------------------------+
int CMarketCollection::Refresh(void)
  {
   ::ZeroMemory(m_struct_market);
   int number_new=0, total=::OrdersTotal();
   m_list_all_orders.Clear();
   for(int i=0; i<total; i++){
      if(!::OrderSelect(i,SELECT_BY_POS)) continue;
      long ticket=::OrderTicket();
      m_struct_market.hash_sum_acc+=ticket;
      m_struct_market.total_volumes+=::OrderLots();
      ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::OrderType();
      if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_SELL){
         CMarketOrder* order=new CMarketOrder();
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
         m_struct_market.total_positions++;
         }
      else{
         CMarketPending* order=new CMarketPending();
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
         m_struct_market.total_pending++;
         }
      }
   //--- Первый запуск
   if(m_hash_sum_acc_prev==WRONG_VALUE){
      m_hash_sum_acc_prev=m_struct_market.hash_sum_acc;
      m_total_positions_prev=m_struct_market.total_positions;
      m_total_pending_prev=m_struct_market.total_pending;
      m_total_volume_prev=m_struct_market.total_volumes;
      }
   //---
   if(m_struct_market.hash_sum_acc!=m_hash_sum_acc_prev){
      number_new=(m_struct_market.total_pending+m_struct_market.total_positions)-(m_total_positions_prev+m_total_pending_prev);
      Print(FUNC,"Хэш-сумма всех ордеров и позиций изменилась");
      //--- Увеличисля общий объём
      if(::NormalizeDouble(m_struct_market.total_volumes-m_total_volume_prev,3)>0){
         Print(FUNC,"Общий объём увеличился");
         if(m_struct_market.total_positions>m_total_positions_prev) Print(FUNC,"Количество позиций увеличилось");
         if(m_struct_market.total_pending>m_total_pending_prev) Print(FUNC,"Количество ордеров увеличилось");
         //--- Отправка EVENT в управляющий класс CEngine
         // сделать!
         }
      //--- Уменьшился общий объём
      else if(::NormalizeDouble(m_struct_market.total_volumes-m_total_volume_prev,3)<0){
         Print(FUNC,"Общий объём уменьшился");
         if(m_struct_market.total_positions<m_total_positions_prev) Print(FUNC,"Количество позиций уменьшилось");
         if(m_struct_market.total_pending<m_total_pending_prev) Print(FUNC,"Количество ордеров уменьшилось");
         //--- Отправка EVENT в управляющий класс CEngine
         // сделать!
         }
      else{
         // что-то ещё, не пойму пока что именно - не было претендентов ещё
         }
      //---
      m_hash_sum_acc_prev=m_struct_market.hash_sum_acc;
      m_total_positions_prev=m_struct_market.total_positions;
      m_total_pending_prev=m_struct_market.total_pending;
      m_total_volume_prev=m_struct_market.total_volumes;
      }
   //---
   //---
   return number_new;
  }
//+------------------------------------------------------------------+

コントロールクラスは、両方のクラスのRefresh()から返される数値によって、どちらかの変更をキャッチすることができます(テスターの場合)。

//+------------------------------------------------------------------+
//| Таймер                                                           |
//+------------------------------------------------------------------+
void CEngine::OnTimer(void)
  {
   //--- Обновление списка исторических ордеров и позиций
   m_new_history=History.Refresh();
   if(m_new_history>0){
      Print(FUNC,"Изменение в исторических на ",m_new_history);
      //--- реакция
      }
   //--- Обновление списка рыночных ордеров и позиций
   m_new_market=Market.Refresh();
   if(m_new_market!=0){
      Print(FUNC,"Изменение в активных на ",m_new_market);
      //--- реакция
      }
   //---
   Sym.OnTimer();
  }
//+------------------------------------------------------------------+

またはユーザーイベントの中で、まだ実装されていないもの(デモ、実機)。

 
Artyom Trishkin:

IsChange()は、まさにタイマーに実装されているものです(テスト版は未完成)。

IsChangeが5行なのに、なぜ?