internal void Equals_VariousValues_ReturnsExpectedResult( decimal price1, decimal price2, int millisecondsOffset, bool expected) { // Arrange var tick1 = new QuoteTick( this.symbol, Price.Create(price1), Price.Create(5), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch()); var tick2 = new QuoteTick( this.symbol, Price.Create(price2), Price.Create(5), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch() + Duration.FromMilliseconds(millisecondsOffset)); // Act var result1 = tick1.Equals(tick2); var result2 = tick1 == tick2; // Assert Assert.Equal(expected, result1); Assert.Equal(expected, result2); }
internal void CanSerializeAndDeserialize_TickDataResponse() { // Arrange var dataSerializer = new QuoteTickSerializer(); var datetimeFrom = StubZonedDateTime.UnixEpoch() + Duration.FromMinutes(1); var datetimeTo = datetimeFrom + Duration.FromMinutes(1); var symbol = new Symbol("AUD/USD", new Venue("FXCM")); var tick1 = new QuoteTick( symbol, Price.Create(1.00000m), Price.Create(1.00000m), Quantity.One(), Quantity.One(), datetimeFrom); var tick2 = new QuoteTick( symbol, Price.Create(1.00010m), Price.Create(1.00020m), Quantity.One(), Quantity.One(), datetimeTo); var ticks = new[] { tick1, tick2 }; var correlationId = Guid.NewGuid(); var id = Guid.NewGuid(); var metadata = new Dictionary <string, string> { { "Symbol", symbol.Value } }; var serializedTicks = dataSerializer.Serialize(ticks); var data = dataSerializer.SerializeBlob(serializedTicks, metadata); var response = new DataResponse( data, typeof(Tick[]).Name, dataSerializer.BlobEncoding, correlationId, id, StubZonedDateTime.UnixEpoch()); // Act var serializedResponse = this.serializer.Serialize(response); var deserializedResponse = (DataResponse)this.serializer.Deserialize(serializedResponse); var deserializedData = dataSerializer.DeserializeBlob(deserializedResponse.Data); // Assert Assert.Equal(response, deserializedResponse); Assert.Equal(tick1, deserializedData[0]); Assert.Equal(tick2, deserializedData[1]); Assert.Equal(correlationId, deserializedResponse.CorrelationId); this.Output.WriteLine(Convert.ToBase64String(serializedResponse)); this.Output.WriteLine(Encoding.UTF8.GetString(serializedResponse)); }
public void Add(QuoteTick tick) { if (this.quoteTickDatabase.TryGetValue(tick.Symbol, out var tickList)) { tickList.Add(tick); } else { this.quoteTickDatabase[tick.Symbol] = new List <QuoteTick> { tick }; } }
/// <inheritdoc /> public void Ingest(QuoteTick tick) { var keyBidPrices = KeyProvider.GetPricesKey(tick.Symbol, PriceType.Bid); var keyAskPrices = KeyProvider.GetPricesKey(tick.Symbol, PriceType.Ask); var keyBidSizes = KeyProvider.GetSizesKey(tick.Symbol, PriceType.Bid); var keyAskSizes = KeyProvider.GetSizesKey(tick.Symbol, PriceType.Ask); this.CheckPricesTimeSeries(keyBidPrices, tick.Symbol, PriceType.Bid); this.CheckPricesTimeSeries(keyAskPrices, tick.Symbol, PriceType.Ask); this.CheckSizesTimeSeries(keyBidSizes, tick.Symbol, PriceType.Bid); this.CheckSizesTimeSeries(keyAskSizes, tick.Symbol, PriceType.Ask); var timestamp = new TimeStamp(tick.Timestamp.ToInstant().ToUnixTimeMilliseconds()); IReadOnlyCollection <(string, TimeStamp, double)> input = new (string, TimeStamp, double)[]
internal void ToSerializableString_ReturnsExpectedString() { // Arrange // Act var tick = new QuoteTick( this.symbol, Price.Create(1.00000m), Price.Create(1.00010m), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch()); // Assert Assert.Equal("1.00000,1.00010,1,1,0", tick.ToSerializableString()); }
internal void ToString_ReturnsExpectedString() { // Arrange // Act var tick = new QuoteTick( this.symbol, Price.Create(1.00000m), Price.Create(1.00010m), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch()); // Assert Assert.Equal("AUD/USD.FXCM,1.00000,1.00010,1,1,1970-01-01T00:00:00.000Z", tick.ToString()); }
public void OnMessage(MarketDataSnapshotFullRefresh message) { Debug.NotNull(this.dataGateway, nameof(this.dataGateway)); message.GetGroup(1, this.mdBidGroup); message.GetGroup(2, this.mdAskGroup); var tick = new QuoteTick( this.GetSymbol(message.GetField(Tags.Symbol)), Price.Create(this.mdBidGroup.GetDecimal(Tags.MDEntryPx)), Price.Create(this.mdAskGroup.GetDecimal(Tags.MDEntryPx)), Quantity.One(), Quantity.One(), this.tickTimestampProvider()); this.dataGateway?.OnData(tick); }
internal void InitializedTick_WithUnixTimeMs_HasExpectedProperties() { // Arrange // Act var tick = new QuoteTick( this.symbol, Price.Create(1.00000m), Price.Create(1.00000m), Quantity.One(), Quantity.One(), 1000); // Assert Assert.Equal("AUD/USD", tick.Symbol.Code); Assert.Equal(decimal.One, tick.Bid.Value); Assert.Equal(decimal.One, tick.Ask.Value); Assert.Equal(1970, tick.Timestamp.Year); }
internal void FromString_WithValidString_ReturnsExpectedTick() { // Arrange var tick = new QuoteTick( this.symbol, Price.Create(1.00000m), Price.Create(1.00000m), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch()); // Act var tickString = tick.ToSerializableString(); var result = QuoteTick.FromSerializableString(this.symbol, tickString); // Assert Assert.Equal(tick, result); }
/// <summary> /// Return the positions unrealized PnL (not including costs, in the position symbols quote currency). /// </summary> /// <param name="last">The position symbols last tick.</param> /// <returns>The PnL as a decimal.</returns> public Money UnrealizedPnl(QuoteTick last) { Debug.EqualTo(this.Symbol, last.Symbol, nameof(last.Symbol)); switch (this.MarketPosition) { case MarketPosition.Long: return(this.CalculatePnl(this.AverageOpenPrice, last.Bid.Value, this.Quantity)); case MarketPosition.Short: return(this.CalculatePnl(this.AverageOpenPrice, last.Ask.Value, this.Quantity)); case MarketPosition.Flat: return(Money.Zero(this.BaseCurrency)); default: throw ExceptionFactory.InvalidSwitchArgument(this.MarketPosition, nameof(this.MarketPosition)); } }
/// <summary> /// Return the positions unrealized return. /// </summary> /// <param name="last">The position symbols last tick.</param> /// <returns>The return as a double.</returns> public double UnrealizedReturn(QuoteTick last) { Debug.EqualTo(this.Symbol, last.Symbol, nameof(last.Symbol)); switch (this.MarketPosition) { case MarketPosition.Long: return(this.CalculateReturn(this.AverageOpenPrice, last.Bid.Value)); case MarketPosition.Short: return(this.CalculateReturn(this.AverageOpenPrice, last.Ask.Value)); case MarketPosition.Flat: return(0); default: throw ExceptionFactory.InvalidSwitchArgument(this.MarketPosition, nameof(this.MarketPosition)); } }
/// <summary> /// Return the positions total PnL (sum of realized and unrealized PnL, not including costs, /// in the position symbols quote currency). /// </summary> /// <param name="last">The position symbols last tick.</param> /// <returns>The total PnL as a <see cref="decimal"/>.</returns> public Money TotalPnl(QuoteTick last) { Debug.EqualTo(this.Symbol, last.Symbol, nameof(last.Symbol)); return(this.RealizedPnl.Add(this.UnrealizedPnl(last))); }
/// <summary> /// Return the positions total return (sum of realized and unrealized returns). /// </summary> /// <param name="last">The position symbols last tick.</param> /// <returns>The total return as a <see cref="double"/>.</returns> public double TotalReturn(QuoteTick last) { Debug.EqualTo(this.Symbol, last.Symbol, nameof(last.Symbol)); return(this.RealizedReturn + this.UnrealizedReturn(last)); }
/// <summary> /// Return the positions total points (sum of realized and unrealized points). /// </summary> /// <param name="last">The position symbols last tick.</param> /// <returns>The total points as a <see cref="decimal"/>.</returns> public decimal TotalPoints(QuoteTick last) { Debug.EqualTo(this.Symbol, last.Symbol, nameof(last.Symbol)); return(this.RealizedPoints + this.UnrealizedPoints(last)); }
/// <inheritdoc /> public void OnData(QuoteTick tick) { throw new System.NotImplementedException(); }
internal void GetMidBars_WithTicksCreatingBar_ReturnsExpectedBar() { // Arrange var audusd = StubInstrumentProvider.AUDUSD(); // var barType = StubBarType.AUDUSD_OneMinuteMid(); this.repository.Update(audusd); var tick0 = new QuoteTick( audusd.Symbol, Price.Create(1.00001, 5), Price.Create(1.00010, 5), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch()); var tick1 = new QuoteTick( audusd.Symbol, Price.Create(1.00000, 5), Price.Create(1.00010, 5), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch() + Duration.FromSeconds(60)); var tick2 = new QuoteTick( audusd.Symbol, Price.Create(1.00030, 5), Price.Create(1.00040, 5), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch() + Duration.FromSeconds(62)); var tick3 = new QuoteTick( audusd.Symbol, Price.Create(0.99980, 5), Price.Create(0.99990, 5), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch() + Duration.FromSeconds(63)); var tick4 = new QuoteTick( audusd.Symbol, Price.Create(1.00001, 5), Price.Create(1.00004, 5), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch() + Duration.FromSeconds(119)); var tick5 = new QuoteTick( audusd.Symbol, Price.Create(1.00001, 5), Price.Create(1.00011, 5), Quantity.One(), Quantity.One(), StubZonedDateTime.UnixEpoch() + Duration.FromSeconds(121)); this.repository.Ingest(tick0); this.repository.Ingest(tick1); this.repository.Ingest(tick2); this.repository.Ingest(tick3); this.repository.Ingest(tick4); this.repository.Ingest(tick5); // var expected = new Bar( // Price.Create(1.000050, 6), // Price.Create(1.000350, 6), // Price.Create(0.999850, 6), // Price.Create(1.000025, 6), // Quantity.Create(8), // StubZonedDateTime.UnixEpoch() + Duration.FromSeconds(120)); // Act // var result = this.repository.GetBars(barType, null, null, 1); // Assert // TODO: System.InvalidCastException : Specified cast is not valid. (inside StackExchange.Redis) // Assert.Equal(6, this.repository.TicksCount(audusd.Symbol)); // Assert.True(this.repository.BarsExist(barType)); // Assert.Equal(2, this.repository.BarsCount(barType)); // Assert.Single(result.Bars); // Assert.Equal(expected, result.Bars[0]); }
/// <inheritdoc /> public void SendToBus(QuoteTick data) { this.quoteBus.PostData(data); }
internal void GivenTickDataRequest_WithTicks_ReturnsValidTickDataResponse() { // Arrange var provider = new TickProvider( this.container, this.messagingAdapter, this.repository, this.tickSerializer, new TradeTickSerializer()); provider.Start().Wait(); var datetimeFrom = StubZonedDateTime.UnixEpoch() + Duration.FromMinutes(1); var datetimeTo = datetimeFrom + Duration.FromMinutes(1); var symbol = new Symbol("AUD/USD", new Venue("FXCM")); var tick1 = new QuoteTick( symbol, Price.Create(1.00000m), Price.Create(1.00000m), Quantity.One(), Quantity.One(), datetimeFrom); var tick2 = new QuoteTick( symbol, Price.Create(1.00010m), Price.Create(1.00020m), Quantity.One(), Quantity.One(), datetimeTo); this.repository.Ingest(tick1); this.repository.Ingest(tick2); var query = new Dictionary <string, string> { { "DataType", "QuoteTick[]" }, { "Symbol", symbol.Value }, { "FromDateTime", StubZonedDateTime.UnixEpoch().ToIso8601String() }, { "ToDateTime", StubZonedDateTime.UnixEpoch().ToIso8601String() }, { "Limit", "0" }, }; var request = new DataRequest( query, Guid.NewGuid(), StubZonedDateTime.UnixEpoch()); // Act var response = (DataResponse)provider.FindData(request); var ticks = this.tickSerializer.DeserializeBlob(response.Data); // Assert Assert.Equal(typeof(DataResponse), response.Type); Assert.Equal(2, ticks.Length); Assert.Equal(tick1, ticks[0]); Assert.Equal(tick2, ticks[1]); }
private void OnMessage(QuoteTick tick) { this.Publish($"{Quote}:{tick.Symbol.Value}", this.quoteSerializer.Serialize(tick)); }
/// <inheritdoc /> public void Ingest(QuoteTick tick) { this.Add(tick); }
/// <summary> /// Send the given quote tick to the data bus. /// </summary> /// <param name="data">The data to send.</param> protected void SendToBus(QuoteTick data) { this.dataBusAdapter.SendToBus(data); }
/// <inheritdoc /> public void OnData(QuoteTick tick) { this.SendToBus(tick); }