ExecuteSellAsync method is being called twice at the same time and as you can see on the logs below. It works fine when I put 15 seconds on Observable.Interval(TimeSpan.FromSeconds(15))
. How can I prevent that situation? Maybe something like locking or I don't know.
2021-02-12 19:04:09 [11] DEBUG LiveTradeManager Order ID: 263010769 | Pair: DOGEUSDT | Order side: Sell | Status: New | Price: 0.06783960 | Last filled price: 0.00000000 | Stop price: 0.00000000 | Quantity: 0.00000000 | Quote quantity: 0.00000000 | Commission: 0
2021-02-12 19:04:09 [11] DEBUG LiveTradeManager Order ID: 263010769 | Pair: DOGEUSDT | Order side: Sell | Status: Filled | Price: 0.06783960 | Last filled price: 0.06784260 | Stop price: 0.00000000 | Quantity: 5420.00000000 | Quote quantity: 367.70689200 | Commission: 0.00201210 BNB
2021-02-12 19:04:09 [11] DEBUG LiveTradeManager Sell order was filled | Close date: 2021/02/12 17:04:09 | Close rate (price): 0.06784260
2021-02-12 19:04:13 [9] INFO Wallets Wallets synced.
2021-02-12 19:04:14 [10] DEBUG LiveTradeManager Timer triggered. Price: 0.06783910 | Timestamp: 2/12/2021 5:03:00 PM | Close: 0.06790680
2021-02-12 19:04:17 [9] DEBUG BinanceSpotClient Limit sell order has failed | Error code: -2010 | Error message: Account has insufficient balance for requested action. | Pair: DOGEUSDT | Quantity: 0.00000000 | Price: 0.06782540
_throttlerObservable = Observable.Interval(TimeSpan.FromSeconds(5))
.SelectMany(_ => Observable.FromAsync(async () =>
{
var lastCandle = _candles.Last();
_logger.Debug($"Timer triggered. Price: {_ticker.LastPrice} | Open time: {lastCandle.Timestamp} | Close: {lastCandle.Close}");
if (_orderSide == OrderSide.Sell)
{
var trade = _trades.FirstOrDefault(e => e.Pair.Equals(_tradeOptions.Pair) && e.IsOpen);
if (trade.NotNull())
{
var shouldSell = _tradingStrategy.ShouldSell(trade, _ticker.LastPrice, _tradeAdvice);
if (shouldSell.SellFlag)
{
await ExecuteSellAsync(trade, lastCandle.Timestamp, shouldSell.SellType).ConfigureAwait(false);
}
}
}
}))
.Subscribe();
Edit
I see what the problem is. _tradingStrategy.ShouldSell takes a few seconds to execute and the next execution starts executing the next check in the same time. Can I use lock
into that logic?
That's what solves it but I need to lock the entire check:
bool test = false;
public (bool SellFlag, SellType SellType) ShouldSell(Trade trade, decimal rate, TradeAdvice tradeAdvice, decimal? low = null, decimal? high = null)
{
if (!test)
{
test = true;
// my logic is here. It takes a few seconds.
test = false;
}
return (false, SellType.None);
}
Edit2
A testable code. Observable.Interval
is executed on each second and ShouldSellAsync's logic takes 5 seconds to execute. Once _completed becomes true
, the message is no longer printed. It executes the message 5 times, when I expect it only once.
using System;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace RxNETDispose
{
class Program
{
private static bool _completed = false;
public static async Task ShouldSellAsync()
{
if (!_completed)
{
await Task.Delay(5000);
Console.WriteLine($"{DateTime.UtcNow} - ShouldSell called");
_completed = true;
}
}
static void Main(string[] args)
{
Observable.Interval(TimeSpan.FromSeconds(1))
.SelectMany(_ => Observable.FromAsync(async () =>
{
await ShouldSellAsync().ConfigureAwait(false);
}))
.Subscribe();
Console.ReadLine();
}
}
}