public static void Publish(string exchange, Orderbook message, string routingKey = null) => Channel(TheRandom.Pair(Dimension)) .BasicPublish( exchange, body: Serialize(message), routingKey: routingKey ?? string.Empty, mandatory: false, basicProperties: new BasicProperties { Persistent = false, DeliveryMode = 1 });
public Orderbook(string assetPairId, decimal bid, decimal ask, int depth) { AssetPairId = assetPairId; var jitter = TheRandom.Range(1, Program.Settings.books.bestPriceDeviation); bid *= jitter; ask *= jitter; for (var(i, offset) = (0, 0.001m * (ask - bid)); i < depth; offset = Max(0.001m, Min((ask - bid) * i / depth, offset * i++))) { // volume = 10 * (i * i + 1) Bids.Add(Level(bid - i * offset, Vol(i))); Asks.Add(Level(ask + i * offset, Vol(i))); } }
private static decimal Vol(int i) => TheRandom.In(10 * ((i - 1) * (i - 1) + 1), 10 * (i * i + 1));
public static void Main(string[] args) { Settings = JsonConvert.DeserializeObject <Settings>(File.ReadAllText(@"./input.json")); RabbitMqPublisher.ConnectionString = new Uri(Settings.rabbitMq.connString.AppendPathSegment("%2f")); var headers = new { api_key = "margintrading", Content_Type = "application/json" }; if (!string.IsNullOrEmpty(Settings.rabbitMq.fxRatesExchange)) { Log("Pre-populating FxRates"); var pairs = Settings.mtSettingsService .AppendPathSegment("api/assetPairs") .WithHeaders(headers) .GetJsonListAsync().Result .Select(x => (string)x.Id).OrderBy(x => x).ToArray(); var oldFx = Settings.mtTradingCore .AppendPathSegment("api/prices/bestFx") .WithHeaders(headers) .PostJsonAsync(new { pairs }).ReceiveJson <Dictionary <string, dynamic> >().Result; var fxRates = pairs.Select(i => (id: i, mid: oldFx.ContainsKey(i) ? (decimal)oldFx[i].Bid : TheRandom.In(Settings.defaults.bid, Settings.defaults.ask))).ToList(); fxRates.ForEach(p => RabbitMqPublisher.Publish( exchange: Settings.rabbitMq.fxRatesExchange, message: new Orderbook( assetPairId: p.id, bid: p.mid, ask: p.mid, depth: 1))); Log("FxRates have been pre-populated"); Log("Waiting 5 seconds after burst"); Thread.Sleep(5000); } var instruments = Settings.mtSettingsService .AppendPathSegment("api/tradingInstruments") .WithHeaders(headers) .GetJsonListAsync().Result .Select(x => (string)x.Instrument).OrderBy(x => x).ToArray(); Log($"Trading instruments discovered: {instruments.Length}"); if (!string.IsNullOrEmpty(Settings.instrumentRegex)) { instruments = instruments.Where(x => new Regex(Settings.instrumentRegex).IsMatch(x)).ToArray(); } var oldQuotes = Settings.mtTradingCore .AppendPathSegment("api/prices/best") .WithHeaders(headers) .PostJsonAsync(new { instruments }).ReceiveJson <Dictionary <string, dynamic> >().Result; Log($"Trading quote history exists for {oldQuotes.Count} pairs"); var quotes = instruments.Select(i => oldQuotes.ContainsKey(i) ? (id: i, bid: (decimal)oldQuotes[i].Bid, ask: (decimal)oldQuotes[i].Ask) : (id: i, Settings.defaults.bid, Settings.defaults.ask)).ToList(); Log($"Operational instruments: {quotes.Count}"); if (quotes.Count.Equals(0)) { return; } var cycleCount = 0; var ramp = Settings.publishingRate.initial; while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Enter)) { var sw = Stopwatch.StartNew(); var target = Stopwatch.Frequency / (ramp += Settings.publishingRate.increment * (Min(Settings.publishingRate.target, ++cycleCount) <= Floor(ramp) ? 0 : cycleCount = 1)); Log($"Current publishing rate: {ramp}"); for (var i = 0; i < quotes.Count; sw.Blink(target * i++ / quotes.Count)) { RabbitMqPublisher.Publish( exchange: Settings.rabbitMq.orderBooksExchange, message: new Orderbook( quotes[i].id, quotes[i].bid, quotes[i].ask, depth: Settings.books.depth )); } sw.Blink(target); } Console.ReadKey(); }