public void Publish(string tickerSymbol, ITradeEvent @event)
        {
            var eventType = @event.ToTradeEventType();
            var topic     = ToTopic(tickerSymbol, eventType);

            _mediator.Tell(new Publish(topic, @event));
        }
        public async override Task OnEvent(ITradeEvent @event)
        {
            //process trade...
            await Task.Delay(1000);

            var isRejected = _rand.Next(0, 4) == 0;

            if (isRejected)
            {
                await Emit(new TradeRejected()
                {
                    TradeId = @event.TradeId
                });

                _logger.LogInformation($"Trade {@event.TradeId} has been rejected");
            }
            else
            {
                await Emit(new TradeValidated()
                {
                    TradeId = @event.TradeId
                });

                _logger.LogInformation($"Trade {@event.TradeId} has been validated");
            }
        }
        private void VerifySerialization(ITradeEvent trade)
        {
            var serializer   = Sys.Serialization.FindSerializerFor(trade).As <TradeEventSerializer>();
            var serialized   = serializer.ToBinary(trade);
            var manifest     = serializer.Manifest(trade);
            var deserialized = serializer.FromBinary(serialized, manifest);

            deserialized.Should().Be(trade);
        }
        private void ProcessBid(Bid bid, Confirmation confirmation)
        {
            var events = _matchingEngine.WithBid(bid);
            var persistableEvents = new ITradeEvent[] { bid }.Concat <ITradeEvent>(events); // bid needs to go before Fill / Match

            _log.Info("[{0}][{1}] - {2} units @ {3} per unit", TickerSymbol, bid.ToTradeEventType(), bid.BidQuantity,
                      bid.BidPrice);

            PersistAll(persistableEvents, @event => { PersistTrade(@event, confirmation); });
        }
예제 #5
0
        public async override Task OnEvent(ITradeEvent @event)
        {
            await Emit(new TradeBooked()
            {
                TradeId   = @event.TradeId,
                TradeBook = _tradeBooks.Random()
            });

            _logger.LogInformation($"Trade {@event.TradeId} has been booked");
        }
        private void ProcessAsk(Ask ask, Confirmation confirmation)
        {
            var events = _matchingEngine.WithAsk(ask);
            var persistableEvents = new ITradeEvent[] { ask }.Concat <ITradeEvent>(events); // ask needs to go before Fill / Match


            _log.Info("[{0}][{1}] - {2} units @ {3} per unit", TickerSymbol, ask.ToTradeEventType(), ask.AskQuantity,
                      ask.AskPrice);

            PersistAll(persistableEvents, @event => { PersistTrade(@event, confirmation); });
        }
        public void Publish(string tickerSymbol, ITradeEvent @event)
        {
            var eventType = @event.ToTradeEventType();

            EnsureSub(eventType);

            foreach (var sub in _subscribers[eventType])
            {
                sub.Tell(@event);
            }
        }
        private void PersistTrade(ITradeEvent @event, Confirmation confirmation)
        {
            if (confirmation != null && (@event is Ask || @event is Bid))
            {
                // need to use the ID of the original sender to satisfy the PersistenceSupervisor
                Sender.Tell(confirmation);
            }

            _publisher.Publish(TickerSymbol, @event);

            // Take a snapshot every N messages to optimize recovery time
            if (LastSequenceNr % SnapshotInterval == 0)
            {
                SaveSnapshot(_matchingEngine.GetSnapshot());
            }
        }
예제 #9
0
        public async override Task OnEvent(ITradeEvent @event)
        {
            var trade = await _repository.Get(@event.TradeId);

            @event.Handle(trade);

            await _repository.Update(trade);

            if (@event is TradeCreated)
            {
                _logger.LogInformation($"Trade {@event.TradeId} has been acknowledged");

                await Emit(new TradeAcknowleged()
                {
                    TradeId = @event.TradeId
                });
            }
        }
예제 #10
0
        public static TradeEventType ToTradeEventType(this ITradeEvent @event)
        {
            switch (@event)
            {
            case Bid b:
                return(TradeEventType.Bid);

            case Ask a:
                return(TradeEventType.Ask);

            case Fill f:
                return(TradeEventType.Fill);

            case Match m:
                return(TradeEventType.Match);

            default:
                throw new ArgumentOutOfRangeException($"[{@event}] is not a supported trade event type.", nameof(@event));
            }
        }
        public Task Emit(ITradeEvent @event)
        {
            using (var connection = _connectionFactory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    var payload = JsonConvert.SerializeObject(@event);
                    var body    = Encoding.UTF8.GetBytes(payload);

                    channel.BasicPublish(
                        exchange: _exchangeName,
                        routingKey: EventServiceName,
                        basicProperties: null,
                        body: body
                        );

                    _logger.LogInformation($"Emitted event {@event.GetType()}");
                }
            }

            return(Task.CompletedTask);
        }
예제 #12
0
        public void FireEvent(ITradeEvent fired)
        {
            if (fired == null)
                throw new ArgumentNullException(nameof(fired));

            var key = fired.GetType();

            if (!delegates.ContainsKey(key))
                return;

            EventCallback callbacks;
            while (!delegates.TryGetValue(key, out callbacks))
            { }

            try
            {
                callbacks.Invoke(fired);
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
            }
        }
예제 #13
0
        private void Commands()
        {
            Command <ConfirmableMessage <Ask> >(a =>
            {
                // For the sake of efficiency - update orderbook and then persist all events
                var events            = _matchingEngine.WithAsk(a.Message);
                var persistableEvents = new ITradeEvent[] { a.Message }.Concat <ITradeEvent>(events); // ask needs to go before Fill / Match

                PersistAll(persistableEvents, @event =>
                {
                    _log.Info("[{0}][{1}] - {2} units @ {3} per unit", TickerSymbol, @event.ToTradeEventType(), a.Message.AskQuantity, a.Message.AskPrice);
                    if (@event is Ask)
                    {
                        // need to use the ID of the original sender to satisfy the PersistenceSupervisor
                        //_confirmationActor.Tell(new Confirmation(a.ConfirmationId, a.SenderId));
                    }
                    _publisher.Publish(TickerSymbol, @event);

                    // Take a snapshot every N messages to optimize recovery time
                    if (LastSequenceNr % SnapshotInterval == 0)
                    {
                        SaveSnapshot(_matchingEngine.GetSnapshot());
                    }
                });
            });

            Command <ConfirmableMessage <Bid> >(b =>
            {
                // For the sake of efficiency -update orderbook and then persist all events
                var events            = _matchingEngine.WithBid(b.Message);
                var persistableEvents = new ITradeEvent[] { b.Message }.Concat <ITradeEvent>(events); // bid needs to go before Fill / Match

                PersistAll(persistableEvents, @event =>
                {
                    _log.Info("[{0}][{1}] - {2} units @ {3} per unit", TickerSymbol, @event.ToTradeEventType(), b.Message.BidQuantity, b.Message.BidPrice);
                    if (@event is Bid)
                    {
                        //_confirmationActor.Tell(new Confirmation(b.ConfirmationId, PersistenceId));
                    }
                    _publisher.Publish(TickerSymbol, @event);

                    // Take a snapshot every N messages to optimize recovery time
                    if (LastSequenceNr % SnapshotInterval == 0)
                    {
                        SaveSnapshot(_matchingEngine.GetSnapshot());
                    }
                });
            });

            Command <SaveSnapshotSuccess>(success =>
            {
                //DeleteMessages(success.Metadata.SequenceNr);
                DeleteSnapshots(new SnapshotSelectionCriteria(success.Metadata.SequenceNr));
            });

            /*
             * Handle subscriptions directly in case we're using in-memory, local pub-sub.
             */
            CommandAsync <TradeSubscribe>(async sub =>
            {
                try
                {
                    var ack = await _subscriptionManager.Subscribe(sub.TickerSymbol, sub.Events, sub.Subscriber);
                    Context.Watch(sub.Subscriber);
                    sub.Subscriber.Tell(ack);
                }
                catch (Exception ex)
                {
                    _log.Error(ex, "Error while processing subscription {0}", sub);
                    sub.Subscriber.Tell(new TradeSubscribeNack(sub.TickerSymbol, sub.Events, ex.Message));
                }
            });

            CommandAsync <TradeUnsubscribe>(async unsub =>
            {
                try
                {
                    var ack = await _subscriptionManager.Unsubscribe(unsub.TickerSymbol, unsub.Events, unsub.Subscriber);
                    // leave DeathWatch intact, in case actor is still subscribed to additional topics
                    unsub.Subscriber.Tell(ack);
                }
                catch (Exception ex)
                {
                    _log.Error(ex, "Error while processing unsubscribe {0}", unsub);
                    unsub.Subscriber.Tell(new TradeUnsubscribeNack(unsub.TickerSymbol, unsub.Events, ex.Message));
                }
            });

            CommandAsync <Terminated>(async t =>
            {
                try
                {
                    var ack = await _subscriptionManager.Unsubscribe(TickerSymbol, t.ActorRef);
                }
                catch (Exception ex)
                {
                    _log.Error(ex, "Error while processing unsubscribe for terminated subscriber {0} for symbol {1}", t.ActorRef, TickerSymbol);
                }
            });

            Command <GetOrderBookSnapshot>(s =>
            {
                Sender.Tell(_matchingEngine.GetSnapshot());
            });
        }
예제 #14
0
 public void ShouldMatchEventWithTradeType(ITradeEvent tradeEvent, TradeEventType expectedType)
 {
     tradeEvent.ToTradeEventType().Should().Be(expectedType);
 }
예제 #15
0
 private void Handler(ITradeEvent tradeEvent)
 {
     pubsubservice.Publish("fzf003", tradeEvent, true);
 }
 public void ShouldSerializeTradeEvent(ITradeEvent trade)
 {
     VerifySerialization(trade);
 }
 public abstract Task OnEvent(ITradeEvent @event);
 public void Publish(string topic, ITradeEvent @event, bool sendOneMessageToEachGroup = false)
 {
     _mediator.Tell(new Publish(topic, @event, sendOneMessageToEachGroup));
 }
 public void Send(string actorpath, ITradeEvent @event, bool localAffinity = false)
 {
     _mediator.Tell(new Send(actorpath, @event, localAffinity));
 }
예제 #20
0
 private static void LogTradeEvent(object sender, ITradeEvent e)
 {
     Console.WriteLine("trade event:\n" + e.ToString());
 }