TheBigBearNow Ответов: 2

H C# метод на задаче, выполняющейся более 1 раза иногда, должен быть только 1


Привет всем, у меня есть приложение C# с задачей, этот вызов метода обычно выполняется 1 раз, но каждый раз через некоторое время он будет делать 2 вызова. Я использую это с "реальными деньгами", поэтому выполнение метода более 1 раза неприемлемо. У меня есть задача, которая всегда выполняется в фоновом режиме, проверяя состояние. Как только его встретили, он делает другой метод. Я попытался добавить счетчик, но он происходит дальше в программе, и он все еще выполняет более 1 выполнения. Есть какие-нибудь мысли или предложения?
private async Task ExecuteTradeTask()
        {
            cancelExecuteTask = new CancellationTokenSource();

            tExecuteTask = Task.Run(async () =>
            {
                while (true)
                {
                    cancelExecuteTask.Token.ThrowIfCancellationRequested();
                    var delayTask = Task.Delay(1000); 

                    if (runHistory)
                    {
                        //if (executeTaskRunning)
                        //{
                        try
                        {
                            if (TradesNow.ContainsKey("Trade1B"))
                            {
                                if (TradePriceValidBuy(CurrentTrade.Price, TradesNow["Trade1B"].StopPrice))
                                {
                                    var response = await StopBuyAsync(TradesNow["Trade1B"].StopPrice, TradesNow["Trade1B"].LimitPrice, TradesNow["Trade1B"].CryptoAmount);

                                    //if failure make global guid and global bools and run async
                                    // Set for 'CHECKING' current Trade Status.
                                    currentGUID = response.Id.ToString();
                                    runStatus = true;
                                    trade1B = false;
                                    TradesNow.Remove("Trade1B");
                                    //RefreshTradesToDo();
                                    PrintToDoTradesAsync();

                                    // GetTradeStatusAsync(response.Id.ToString());
                                    if (!tStatusTask.Status.Equals(TaskStatus.Running))
                                    {
                                         await GetTradeStatusAsync();
                                    }
                                    return;
                                }
                        }
   }
                        catch (Exception)
                        {
                            //MessageBox.Show("Trade Created Exception.\n" + ex.Message, "Error",
                            //             MessageBoxButton.OK, MessageBoxImage.Error);
                            return;
                        }
                        // }
                    }
                    await delayTask;
                }
            }, cancelExecuteTask.Token);
    }
private async Task<OrderResponse> StopBuyAsync(decimal stopPrice, decimal limitPrice, decimal cryptoAmount)
        {
            StopOrders stopOrder = new StopOrders(stopPrice, limitPrice, cryptoAmount);
            OrderResponse response;
            try
            {
                response = await tradeClient.StopOrderBuy(stopOrder);
            }
            catch(Exception)
            {
                throw;
            }
            return response;
        }
        public async Task<OrderResponse> StopOrderBuy(StopOrders order)
        {
            //if (!running) {  running = true; }
            //else  running = false;
            OrderResponse response;
            int isValid = 0;

            //if(isValid == 0)
            //{
                try
                {
                    response = await coinbaseProClient.OrdersService.PlaceStopOrderAsync
                        (
                            OrderSide.Buy,
                            ProductType.BtcUsd,
                            order.CryptoAmount,
                            order.LimitPrice,
                            order.StopPrice
                        );
                    isValid++;
                }
                catch(Exception)// ex)
                {
                    throw;// ex;
                }
            //}


            return response;
            ///return isValid;
        }


Что я уже пробовал:

Я попытался добавить счетчик в метод, но это происходило дальше в программе, так что это не сработало. Это происходит не каждый раз, а только иногда. Но мне это нужно, чтобы этого "никогда" не случилось. Я вызываю API для
var response = await StopBuyAsync(TradesNow["Trade1B"].StopPrice, TradesNow["Trade1B"].LimitPrice, TradesNow["Trade1B"].CryptoAmount);

Это та часть, которая может произойти только один раз.

2 Ответов

Рейтинг:
2

Richard MacCutchan

while (true)

Почему вы запускаете этот код в цикле, если он никогда не должен выполняться более одного раза? Я могу только предположить, что существует некоторая ситуация, когда код пропускает оба оператора return.


TheBigBearNow

Мне нужно, чтобы он постоянно проверял условие, и если условие выполнено, то выполняйте метод 1 раз. Условие-это проверка цены, которая меняется каждую секунду.
В настоящее время мой ExecuteTradeTask() делает все это. Но id говорит, что 90% он выполняет только 1 раз, как и предполагалось. Но время от времени он будет исполняться 2-3 раза, что не может произойти, потому что использование реальных денег для совершения сделки более 1 раза не очень хорошо.

Richard MacCutchan

Ну, единственное, что я могу предложить, - это очень внимательно посмотреть на дизайн этого фрагмента кода, потому что пока такая возможность существует, вы не можете на нее полагаться.

TheBigBearNow

Я попытаюсь разорвать его. У меня есть идея вместо того, чтобы вызывать мой метод в потоке, я могу заставить поток установить bool в true, а в отдельном потоке я могу вызвать метод один раз, если он истинен. Я новичок в многопоточных приложениях, в настоящее время у меня есть поток, получающий историю торговли, мой GUI WPF-поток, Поток TradeStatus после выполнения сделки, и у меня был этот поток ExecuteTrade.

Рейтинг:
0

TheBigBearNow

Я думаю, что, возможно, я решил эту проблему:
До сих пор он, кажется, работает нормально, без каких-либо двойных сделок.

Я добавил небольшую задержку после того, как метод делает торговлю.

public async Task<OrderResponse> StopOrderSell(StopOrders order)
       {
           OrderResponse response;

               try
               {
                   response = await coinbaseProClient.OrdersService.PlaceStopOrderAsync
                       (
                           OrderSide.Sell,
                           ProductType.BtcUsd,
                           order.CryptoAmount,
                           order.LimitPrice,
                           order.StopPrice
                       );

                   await Task.Delay(500);
                   return response;
               }
               catch (Exception)// ex)
               {
                   throw;
               }

           return response;
       }


Richard MacCutchan

Таким образом, вы все еще не решили проблему на самом деле. Поиск обходного пути-это все очень хорошо, но это не то решение, на которое вы должны полагаться. Если проблема повторится, что вы будете делать? Удвоить время задержки? И если это все еще произойдет после этого ... ?

CHill60

Кстати, я согласен с Ричардом, что это не очень надежное решение.
Другими словами, вы можете упростить свой код, удалив блок try-catch, который на самом деле ничего не делает, кроме удаления деталей трассировки стека

TheBigBearNow

Вы, ребята, правы, если это случится снова, я понятия не имею..
Я хотел бы иметь решение, где этого не происходит.
Если я удалю свой блок try-catch, если произойдет исключение, не сломается ли тогда моя программа?

TheBigBearNow

Какие-то плохие новые люди.. Это не исправлено, теперь он делает это еще меньше, но произошла двойная сделка. Начать всё с начала...

TheBigBearNow

Поэтому я сделал лог-файл, чтобы посмотреть, поможет ли он мне понять эти двойные сделки.
Вот что мне удалось выяснить. Обычный журнал сверху и дубликат рядом.
06/04/2020 4:39:50 В ExecuteTradeTaskV3 Start
06/04/2020 4:39:50 Цена Действительна B1
06/04/2020 4:39:50 StopBuyV2 - перед вызовом TradeClient
06/04/2020 4:39:50 Торговый Клиент - StopOrderBuy Start
06/04/2020 4:39:50 торговый клиент - StopOrderBuy API Start
06/04/2020 4:39:51 торговый клиент - StopOrderBuy API после
06/04/2020 4:39:52 Торговый Клиент - StopOrderBuy End
06/04/2020 4:39:52 StopBuyV2 - конец метода()
06/04/2020 4:39:52 B1 - после того, как StopBuyV2 вернулся
06/04/2020 4:40:27 В ExecuteTradeTaskV3 Start
06/04/2020 4:40:41 В ExecuteTradeTaskV3 Start
06/04/2020 4:41:28 В ExecuteTradeTaskV3 Start
06/04/2020 4:41:28 Цена Действительна B1
06/04/2020 4:41:28 Цена Действительна B1
06/04/2020 4:41:28 StopBuyV2 - перед вызовом TradeClient
06/04/2020 4:41:29 StopBuyV2 - перед вызовом TradeClient
06/04/2020 4:41:29 Торговый Клиент - StopOrderBuy Start
06/04/2020 4:41:29 Торговый Клиент - StopOrderBuy Start
06/04/2020 4:41:29 торговый клиент - StopOrderBuy API Start
06/04/2020 4:41:29 торговый клиент - StopOrderBuy API Start
06/04/2020 4:41:29 торговый клиент - StopOrderBuy API после
06/04/2020 4:41:29 торговый клиент - StopOrderBuy API после
06/04/2020 4:41:30 Торговый Клиент - StopOrderBuy End
06/04/2020 4:41:30 StopBuyV2 - конец метода()
06/04/2020 4:41:30 B1 - после того, как StopBuyV2 вернулся