Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4b9b6bcba | ||
|
|
84d74a7873 | ||
|
|
8c34280d75 | ||
|
|
474d96ced4 | ||
|
|
1432692a26 |
No files matched your search
@@ -80,7 +80,7 @@ namespace BCG {
|
||||
int id = Convert.ToInt32(skey);
|
||||
PriceStats pstats = kv.Value;
|
||||
var today = DateTime.Now.Date;
|
||||
IBlueRow r = new BlueRow(_pstats_scheam, id, skey, pstats.security.ToString(), today, pstats.open, pstats.close, pstats.settlement);
|
||||
IBlueRow r = new BlueRow(_pstats_scheam, id, skey, pstats.Security.ToString(), today, pstats.Open, pstats.Close, pstats.Settlement);
|
||||
new_state.addRow(r);
|
||||
}
|
||||
DataPacket dp;
|
||||
|
||||
@@ -29,7 +29,7 @@ using System.Reactive.Subjects;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class MarketDataClient : IMarketDataClient {
|
||||
public class MarketDataClient : IMarketDataClient, IDisposable {
|
||||
readonly ISubject<MDConsumer> mdConsumerSrc = new ReplaySubject<MDConsumer>(1);
|
||||
readonly IObservable<ConcurrentDictionary<uint, SecurityMD>> securitiesSrc;
|
||||
readonly List<IDisposable> _resources = new();
|
||||
@@ -195,7 +195,7 @@ public class MarketDataClient : IMarketDataClient {
|
||||
PollStats);
|
||||
|
||||
uint GetSecId(PriceStats stats) =>
|
||||
stats.security.Id;
|
||||
stats.Security.Id;
|
||||
|
||||
TableUpdate<PriceStats, uint> PollStats(TableUpdate<PriceStats, uint> table, long _) {
|
||||
var bd = table.ToBuilder();
|
||||
@@ -229,7 +229,7 @@ public class MarketDataClient : IMarketDataClient {
|
||||
PollTickers);
|
||||
|
||||
uint GetSecId(PriceTicker ticker) =>
|
||||
ticker.security.Id;
|
||||
ticker.Security.Id;
|
||||
|
||||
TableUpdate<PriceTicker, uint> PollTickers(TableUpdate<PriceTicker, uint> table, long _) {
|
||||
var bd = table.ToBuilder();
|
||||
@@ -243,6 +243,9 @@ public class MarketDataClient : IMarketDataClient {
|
||||
}
|
||||
}
|
||||
|
||||
~MarketDataClient() =>
|
||||
Dispose();
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
isDisposed = true;
|
||||
|
||||
@@ -16,8 +16,10 @@ class PollablePriceTicker {
|
||||
PriceTicker ticker;
|
||||
ulong volume;
|
||||
|
||||
public PollablePriceTicker(SecurityMD securityMd) =>
|
||||
public PollablePriceTicker(SecurityMD securityMd) {
|
||||
this.securityMd = securityMd;
|
||||
ticker = mkTicker();
|
||||
}
|
||||
|
||||
public PriceTicker ToTicker() =>
|
||||
ticker;
|
||||
|
||||
@@ -2,46 +2,20 @@
|
||||
namespace Spark.Api.MarketData {
|
||||
using bts.api;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Price/trade statistics for a particular security (slow moving)
|
||||
/// </summary>
|
||||
public readonly struct PriceStats : IEquatable<PriceStats>, IJsonFormatter<PriceStats> {
|
||||
public PriceStats(SecurityImmutable security, double open, double close, double settlement) {
|
||||
this.security = security;
|
||||
this.open = open;
|
||||
this.close = close;
|
||||
this.settlement = settlement;
|
||||
}
|
||||
|
||||
public SecurityImmutable security { get; }
|
||||
public double open { get; }
|
||||
public double close { get; }
|
||||
public double settlement { get; }
|
||||
|
||||
public bool Equals(PriceStats other) =>
|
||||
security.Equals(other.security) &&
|
||||
open.Equals(other.open) &&
|
||||
close.Equals(other.close) &&
|
||||
settlement.Equals(other.settlement);
|
||||
|
||||
public override bool Equals(object? obj) =>
|
||||
obj is PriceStats other && Equals(other);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(security.Id, open, close, settlement);
|
||||
|
||||
public static bool operator ==(PriceStats left, PriceStats right) =>
|
||||
left.Equals(right);
|
||||
|
||||
public static bool operator !=(PriceStats left, PriceStats right) =>
|
||||
!(left == right);
|
||||
public readonly record struct PriceStats(
|
||||
SecurityImmutable Security,
|
||||
double Open,
|
||||
double Close,
|
||||
double Settlement
|
||||
) : IJsonFormatter<PriceStats> {
|
||||
public static System.Object ToJsonObj(PriceStats obj) => new {
|
||||
open = obj.open,
|
||||
close = obj.close,
|
||||
settlement = obj.settlement,
|
||||
security = obj.security.Exchange.ToString() + "." + obj.security.ToString()
|
||||
open = obj.Open,
|
||||
close = obj.Close,
|
||||
settlement = obj.Settlement,
|
||||
security = obj.Security.Exchange.ToString() + "." + obj.Security.ToString()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,106 +3,35 @@ namespace Spark.Api.MarketData {
|
||||
using bts.api;
|
||||
using bts.api.domain;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Price/trade statistics for a particular security (fast moving)
|
||||
/// </summary>
|
||||
public readonly struct PriceTicker : IEquatable<PriceTicker>, IJsonFormatter<PriceTicker> {
|
||||
public PriceTicker(
|
||||
SecurityImmutable security,
|
||||
TickDisplaySettingsImmutable quantity_display,
|
||||
double high,
|
||||
double low,
|
||||
double volume,
|
||||
double bid,
|
||||
double bid_quantity,
|
||||
double ask,
|
||||
double ask_quantity,
|
||||
double mark,
|
||||
double last,
|
||||
double last_quantity
|
||||
) {
|
||||
this.security = security;
|
||||
this.quantity_display = quantity_display;
|
||||
this.high = high;
|
||||
this.low = low;
|
||||
this.volume = volume;
|
||||
this.bid = bid;
|
||||
this.bid_quantity = bid_quantity;
|
||||
this.ask = ask;
|
||||
this.ask_quantity = ask_quantity;
|
||||
this.mark = mark;
|
||||
this.last = last;
|
||||
this.last_quantity = last_quantity;
|
||||
}
|
||||
|
||||
public SecurityImmutable security { get; }
|
||||
public TickDisplaySettingsImmutable quantity_display { get; }
|
||||
public double high { get; }
|
||||
public double low { get; }
|
||||
public double volume { get; }
|
||||
public double bid { get; }
|
||||
public double bid_quantity { get; }
|
||||
public double ask { get; }
|
||||
public double ask_quantity { get; }
|
||||
public double mark { get; }
|
||||
public double last { get; }
|
||||
public double last_quantity { get; }
|
||||
|
||||
public bool Equals(PriceTicker other) =>
|
||||
security.Equals(other.security) &&
|
||||
quantity_display.Equals(other.quantity_display) &&
|
||||
high.Equals(other.high) &&
|
||||
low.Equals(other.low) &&
|
||||
volume.Equals(other.volume) &&
|
||||
bid.Equals(other.bid) &&
|
||||
bid_quantity.Equals(other.bid_quantity) &&
|
||||
ask.Equals(other.ask) &&
|
||||
ask_quantity.Equals(other.ask_quantity) &&
|
||||
mark.Equals(other.mark) &&
|
||||
last.Equals(other.last) &&
|
||||
last_quantity.Equals(other.last_quantity);
|
||||
|
||||
public override bool Equals(object? obj) =>
|
||||
obj is PriceTicker other && Equals(other);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
new HashCode()
|
||||
.with_values(new int[] {
|
||||
security.Id.GetHashCode(),
|
||||
high.GetHashCode(),
|
||||
low.GetHashCode(),
|
||||
volume.GetHashCode(),
|
||||
bid.GetHashCode(),
|
||||
bid_quantity.GetHashCode(),
|
||||
ask.GetHashCode(),
|
||||
ask_quantity.GetHashCode(),
|
||||
mark.GetHashCode(),
|
||||
last.GetHashCode(),
|
||||
last_quantity.GetHashCode()
|
||||
})
|
||||
.ToHashCode();
|
||||
|
||||
public static bool operator ==(PriceTicker left, PriceTicker right) =>
|
||||
left.Equals(right);
|
||||
|
||||
public static bool operator !=(PriceTicker left, PriceTicker right) =>
|
||||
!(left == right);
|
||||
public readonly record struct PriceTicker (
|
||||
SecurityImmutable Security,
|
||||
TickDisplaySettingsImmutable QuantityDisplay,
|
||||
double High,
|
||||
double Low,
|
||||
double Volume,
|
||||
double Bid,
|
||||
double BidQuantity,
|
||||
double Ask,
|
||||
double AskQuantity,
|
||||
double Mark,
|
||||
double Last,
|
||||
double LastQuantity
|
||||
) : IJsonFormatter<PriceTicker> {
|
||||
public static System.Object ToJsonObj(PriceTicker obj) => new {
|
||||
security = obj.security.Exchange.ToString() + "." + obj.security.ToString(),
|
||||
high = obj.high,
|
||||
low = obj.low,
|
||||
volume = obj.volume,
|
||||
bid = obj.bid,
|
||||
bid_quantity = obj.bid_quantity,
|
||||
ask = obj.ask,
|
||||
ask_quantity = obj.ask_quantity,
|
||||
mark = obj.mark,
|
||||
last = obj.last,
|
||||
last_quantity = obj.last_quantity
|
||||
security = obj.Security.Exchange.ToString() + "." + obj.Security.ToString(),
|
||||
high = obj.High,
|
||||
low = obj.Low,
|
||||
volume = obj.Volume,
|
||||
bid = obj.Bid,
|
||||
bid_quantity = obj.BidQuantity,
|
||||
ask = obj.Ask,
|
||||
ask_quantity = obj.AskQuantity,
|
||||
mark = obj.Mark,
|
||||
last = obj.Last,
|
||||
last_quantity = obj.LastQuantity
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ class TopOfBookQuoter : IHostedService {
|
||||
// Send a new order for this security.
|
||||
async void SendOrder() {
|
||||
logger.LogInformation("Sending order. {side} {security} {quantity} @ {price}", orderId, bk.Security, orderQty, orderPrice);
|
||||
var res = await sparkClient.CreateLimitOrder(config.Account!, bk.SecurityId, Side.Buy, orderQty, orderPrice);
|
||||
var res = await sparkClient.CreateLimitOrder(config.Account!, bk.SecurityId, Side.Buy, orderQty, orderPrice, null);
|
||||
if (res.ErrorCode == bts.api.orderman.OrderError.Ok) {
|
||||
logger.LogDebug("Sent order. id: {orderId}, security: {security}", orderId, bk.Security);
|
||||
} else {
|
||||
@@ -151,6 +151,7 @@ class TopOfBookQuoter : IHostedService {
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken) {
|
||||
logger.LogInformation("RequoteTopOfBookDemo stopping");
|
||||
Disposable.Dispose(ref subscription);
|
||||
logger.LogInformation("RequoteTopOfBookDemo stopped");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -91,6 +91,12 @@ public class AuthenticatedSimpleSparkClient : ISimpleSparkClient, IHostedService
|
||||
public IObservable<IList<TradeInfo>> Trades(SecurityCriteria? securityCriteria) =>
|
||||
simpleClient?.Trades(securityCriteria) ?? simpleClientSubject.Take(1).Select(c => c.Trades(securityCriteria)).FlattenSeries();
|
||||
|
||||
public IObservable<TableUpdate<PriceStats, uint>> PriceStats(SecurityCriteria? securityCriteria) =>
|
||||
simpleClient?.PriceStats(securityCriteria) ?? simpleClientSubject.Take(1).Select(c => c.PriceStats(securityCriteria)).FlattenSeries();
|
||||
|
||||
public IObservable<TableUpdate<PriceTicker, uint>> PriceTicker(SecurityCriteria? securityCriteria) =>
|
||||
simpleClient?.PriceTicker(securityCriteria) ?? simpleClientSubject.Take(1).Select(c => c.PriceTicker(securityCriteria)).FlattenSeries();
|
||||
|
||||
public Task<Response> CreateOrder(OrderDefinition orderDef, double quantity, double price) =>
|
||||
orderOp(cli => cli.CreateOrder(orderDef, quantity, price));
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using bts.api;
|
||||
using bts.api.core;
|
||||
using bts.api.orderman;
|
||||
|
||||
using global::Spark.Api.MarketData;
|
||||
using global::Spark.Api.Orders;
|
||||
|
||||
using mbts.spark;
|
||||
@@ -41,6 +42,12 @@ public class ExecutionFacadeSimpleSparkClient : ISimpleSparkClient {
|
||||
public IObservable<IList<TradeInfo>> Trades(SecurityCriteria? securityCriteria) =>
|
||||
sparkClient.Trades(securityCriteria);
|
||||
|
||||
public IObservable<TableUpdate<PriceStats, uint>> PriceStats(SecurityCriteria? securityCriteria) =>
|
||||
sparkClient.PriceStats(securityCriteria);
|
||||
|
||||
public IObservable<TableUpdate<PriceTicker, uint>> PriceTicker(SecurityCriteria? securityCriteria) =>
|
||||
sparkClient.PriceTicker(securityCriteria);
|
||||
|
||||
public Task<Response> CreateOrder(OrderDefinition orderDef, double quantity, double price) {
|
||||
logger.LogInformation("CreateOrder {account} {tag} {securityId} {side} {quantity} @ {price}", orderDef.Account, orderDef.Tag, orderDef.SecurityKey, orderDef.Side, quantity, price);
|
||||
return Task.FromResult(facadeResponse());
|
||||
|
||||
@@ -4,6 +4,7 @@ using bts.api;
|
||||
using bts.api.core;
|
||||
using bts.api.orderman;
|
||||
|
||||
using global::Spark.Api.MarketData;
|
||||
using global::Spark.Api.Orders;
|
||||
|
||||
using mbts.spark;
|
||||
@@ -15,6 +16,8 @@ public interface ISimpleSparkClient {
|
||||
IObservable<TableUpdate<SecurityImmutable, uint>> Securities(SecurityCriteria? securityCriteria);
|
||||
IObservable<TableUpdate<BookRecord, uint>> Books(SecurityCriteria? securityCriteria);
|
||||
IObservable<IList<TradeInfo>> Trades(SecurityCriteria? securityCriteria);
|
||||
IObservable<TableUpdate<PriceStats, uint>> PriceStats(SecurityCriteria? securityCriteria);
|
||||
IObservable<TableUpdate<PriceTicker, uint>> PriceTicker(SecurityCriteria? securityCriteria);
|
||||
|
||||
// Orders, Positions, and Pnl
|
||||
IObservable<TableUpdate<OrderRecordTupleWithRoot, uint>> Orders(string? account, SecurityCriteria? securityCriteria);
|
||||
|
||||
@@ -249,6 +249,12 @@ public class SimpleSparkClient : ISimpleSparkClient, IDisposable {
|
||||
: Observable.Return<PositionRecord?>(null))
|
||||
.FlattenSeries();
|
||||
|
||||
public IObservable<TableUpdate<PriceStats, uint>> PriceStats(SecurityCriteria? securityCriteria) =>
|
||||
mdClient.PriceStats(securityCriteria);
|
||||
|
||||
public IObservable<TableUpdate<PriceTicker, uint>> PriceTicker(SecurityCriteria? securityCriteria) =>
|
||||
mdClient.PriceTicker(securityCriteria);
|
||||
|
||||
public IObservable<IList<TradeInfo>> Trades(SecurityCriteria? securityCriteria) {
|
||||
var tradesSource = mdClient.Trades();
|
||||
if (securityCriteria?.is_defined() ?? false) {
|
||||
|
||||
Reference in new issue
Block a user