public async Task DoWork(IBaseSocketExchange baseExchange, CancellationToken token) { var pairs = dbService.GetArbitragePairs("market", baseExchange.Name, counterExchange.Name).Select(p => new ArbitragePair(p)); SocketTradeHandler handler = ProcessTrade; foreach (var pair in pairs) { baseExchange.RegisterPair(pair, handler); } baseExchange.SubscribeTrades(token); Parallel.ForEach(pairs, pair => { try { ProcessOrderBook(baseExchange, pair, token).Wait(); } catch (Exception ex) { logger.Error(ex); } }); await Task.FromResult(0); }
public async Task ProcessTrade(IBaseSocketExchange baseExchange, ArbitragePair pair, IMatch trade) { if (trade.Symbol == pair.Symbol && trade.QuantityFilled > 0) { logger.Trace(JsonConvert.SerializeObject(trade, Formatting.Indented)); await PlaceCounterOrder(pair, trade); } }
private void Reset(IBaseSocketExchange baseExchange) { foreach (var socket in counterSockets.Values) { socket.Reset(); } counterSockets.Clear(); baseExchange.Reset(); }
public async Task ProcessOrderBook(IBaseSocketExchange baseExchange, ArbitragePair pair, CancellationToken cancellationToken) { var counterSocket = counterExchange.GetSocket(); counterSockets[pair.Symbol] = counterSocket; counterSocket.OnBook += async(book) => { if (!cancellationToken.IsCancellationRequested) { try { decimal counterBuy = Helper.RoundPrice(pair, EngineHelper.GetPriceAtVolumeThreshold(pair.BidMultiplier * pair.TradeThreshold, book.asks)); decimal counterSell = Helper.RoundPrice(pair, EngineHelper.GetPriceAtVolumeThreshold(pair.AskMultiplier * pair.TradeThreshold, book.bids)); //Calculate the BID based off what we can sell for on the counter exchange decimal buy = Helper.RoundPrice(pair, counterSell - (counterSell * pair.BidSpread)); decimal sell = Helper.RoundPrice(pair, counterBuy + (counterBuy * pair.AskSpread)); if (buy >= counterSell) { buy -= pair.TickSize; } if (sell <= counterBuy) { sell += pair.TickSize; } var tasks = new List <Task> { PlaceBuyIOC(baseExchange, pair, buy), PlaceSellIOC(baseExchange, pair, sell) }; await Task.WhenAll(tasks); } catch (AggregateException ae) { ae.Handle((x) => { if (x is ApiException) // This we know how to handle. { logger.Error(((ApiException)x).Content); } return(false); // Let anything else stop the application. }); } } }; counterSocket.SubscribeOrderbook(pair.CounterSymbol); await Task.FromResult(true); }
public void StartEngine(IBaseSocketExchange baseExchange) { Console.WriteLine("Starting Engine V2"); var wtoken = new CancellationTokenSource(); // Set the tasks. var task = (ActionBlock <IBaseSocketExchange>)CreateNeverEndingTask((e, ct) => DoWork(e, ct), wtoken.Token); task.Post(baseExchange); task.Completion.Wait(); }
private async Task PlaceBuyIOC(IBaseSocketExchange baseExchange, ArbitragePair pair, decimal price) { decimal buyQuantity = 0; try { // decimal raw = pair.BidMultiplier * pair.TradeThreshold / price; // buyQuantity = Helper.RoundQuantity(pair, pair.BidMultiplier * pair.TradeThreshold / price); buyQuantity = pair.Increment; if (buyQuantity > 0) { var result = await baseExchange.ImmediateOrCancel("buy", pair.BaseSymbol, buyQuantity, price); Console.WriteLine(string.Format("IOK BUY {0} {1} {2:P2}", pair.Symbol, price, pair.BidSpread)); } else { logger.Error("No Quantity for {0}", pair.Symbol); } } catch (ApiException ae) { if (ae.Content.ToLowerInvariant().Contains("insufficient")) { pair.Status = "error"; dbService.SaveArbitragePair(pair); } logger.Error(JsonConvert.SerializeObject(JsonConvert.DeserializeObject(ae.Content), Formatting.Indented)); } catch (Exception e) { logger.Error(e); Thread.Sleep(1000 * 10); } }