Skip to content

Commit 92c3d86

Browse files
committed
Gateways
1 parent 639b7e8 commit 92c3d86

13 files changed

Lines changed: 173 additions & 93 deletions

File tree

Dashboard/Dashboard/Pages/Gateways/CoinDemo.razor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public partial class CoinDemo
3131
Name = "ETH",
3232
Type = InstrumentEnum.Coins,
3333
TimeFrame = TimeSpan.FromMinutes(1),
34-
Currency = new() { Name = "USDT" }
34+
Currency = new() { Name = "USD" }
3535
}
3636
};
3737

@@ -81,8 +81,8 @@ protected override async Task OnTradeUpdate(Instrument instrument)
8181
var name = instrument.Name;
8282
var price = instrument.Price;
8383
var account = adapter.Account;
84-
var orders = (await adapter.GetOrders(new() { Source = false })).Data;
85-
var positions = (await adapter.GetPositions(new() { Source = false })).Data;
84+
var orders = (await adapter.GetOrders(new() { Source = true })).Data;
85+
var positions = (await adapter.GetPositions(new() { Source = true })).Data;
8686

8787
if (orders.Count is 0 && positions.Count is 0)
8888
{

Dashboard/Dashboard/Pages/Gateways/InterBrokerDemo.razor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ protected override async Task OnTradeUpdate(Instrument instrument)
7979
var name = instrument.Name;
8080
var price = instrument.Price;
8181
var account = adapter.Account;
82-
var orders = (await adapter.GetOrders(new() { Source = false })).Data;
83-
var positions = (await adapter.GetPositions(new() { Source = false })).Data;
82+
var orders = (await adapter.GetOrders(new() { Source = true })).Data;
83+
var positions = (await adapter.GetPositions(new() { Source = true })).Data;
8484

8585
if (orders.Count is 0 && positions.Count is 0)
8686
{

Gateways/Coin/Libs/Grains/ConnectionGrain.cs

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -87,31 +87,17 @@ public override Task<StatusResponse> Disconnect()
8787
/// <param name="instrument"></param>
8888
public override async Task<StatusResponse> Subscribe(Instrument instrument)
8989
{
90-
var descriptor = this.GetDescriptor();
9190
var currency = instrument.Currency.Name;
92-
var instrumentDescriptor = this.GetDescriptor(instrument.Name + currency);
93-
var domGrain = GrainFactory.GetGrain<IDomGrain>(instrumentDescriptor);
94-
var instrumentGrain = GrainFactory.GetGrain<IInstrumentGrain>(instrumentDescriptor);
95-
var positionsGrain = GrainFactory.GetGrain<IPositionsGrain>(descriptor);
96-
var ordersGrain = GrainFactory.GetGrain<IOrdersGrain>(descriptor);
97-
var symbol = new SharedSymbol(TradingMode.Spot, instrument.Name, currency);
98-
var subResponse = await streamer.SubscribeToBookTickerUpdatesAsync(state.Exchange, new SubscribeBookTickerRequest(symbol), async o =>
99-
{
100-
var group = await instrumentGrain.Send(instrument with { Price = MapBook(o) });
101-
102-
observer.StreamPrice(group);
103-
await observer.StreamInstrument(group);
104-
});
91+
var security = new SharedSymbol(TradingMode.Spot, instrument.Name, currency, instrument?.Derivative?.ExpirationDate);
92+
var query = new SubscribeBookTickerRequest(security);
93+
var subResponse = await streamer.SubscribeToBookTickerUpdatesAsync(state.Exchange, query, o => SendStream(instrument, MapPrice(o)));
10594

10695
if (subResponse.Success is false)
10796
{
108-
await streamer.SubscribeToTickerUpdatesAsync(state.Exchange, new SubscribeTickerRequest(symbol), async o =>
97+
switch (true)
10998
{
110-
var group = await instrumentGrain.Send(instrument with { Price = MapPrice(o) });
111-
112-
observer.StreamPrice(group);
113-
await observer.StreamInstrument(group);
114-
});
99+
case true when Equals(state.Exchange, streamer.Coinbase.Exchange): await Coinbase(instrument); break;
100+
}
115101
}
116102

117103
return new()
@@ -120,30 +106,67 @@ public override async Task<StatusResponse> Subscribe(Instrument instrument)
120106
};
121107
}
122108

109+
/// <summary>
110+
/// Stream price
111+
/// </summary>
112+
/// <param name="instrument"></param>
113+
/// <param name="o"></param>
114+
protected virtual async void SendStream(Instrument instrument, Price o)
115+
{
116+
var currency = instrument.Currency.Name;
117+
var instrumentDescriptor = this.GetDescriptor(instrument.Name + currency);
118+
var instrumentGrain = GrainFactory.GetGrain<IInstrumentGrain>(instrumentDescriptor);
119+
var group = await instrumentGrain.Send(instrument with { Price = o });
120+
121+
observer.StreamPrice(group);
122+
123+
await observer.StreamInstrument(group);
124+
}
125+
123126
/// <summary>
124127
/// Map book
125128
/// </summary>
126129
/// <param name="o"></param>
127-
protected virtual Price MapBook(ExchangeEvent<SharedBookTicker> o) => new()
130+
protected virtual Price MapPrice(ExchangeEvent<SharedBookTicker> o) => new()
128131
{
129132
Bid = (double)o.Data.BestBidPrice,
130133
BidSize = (double)o.Data.BestBidQuantity,
131134
Ask = (double)o.Data.BestAskPrice,
132135
AskSize = (double)o.Data.BestAskQuantity,
133-
Time = DateTime.Now.Ticks
136+
Last = (double)((o.Data.BestBidPrice + o.Data.BestAskPrice) / 2),
137+
Time = o.DataTime?.Ticks
134138
};
135139

136140
/// <summary>
137-
/// Map price
141+
/// Subscribe to Coinbase
138142
/// </summary>
139-
/// <param name="o"></param>
140-
protected virtual Price MapPrice(ExchangeEvent<SharedSpotTicker> o) => new()
143+
/// <param name="instrument"></param>
144+
protected virtual Task Coinbase(Instrument instrument)
141145
{
142-
Bid = (double)o.Data.LastPrice,
143-
BidSize = (double)o.Data.LastPrice,
144-
Ask = (double)o.Data.QuoteVolume,
145-
AskSize = (double)o.Data.QuoteVolume,
146-
Time = DateTime.Now.Ticks
147-
};
146+
var security = new SharedSymbol(
147+
TradingMode.Spot,
148+
instrument.Name,
149+
instrument.Currency.Name,
150+
instrument?.Derivative?.ExpirationDate);
151+
152+
var name = streamer.Coinbase.AdvancedTradeApi.FormatSymbol(
153+
security.BaseAsset,
154+
security.QuoteAsset,
155+
security.TradingMode,
156+
security.DeliverTime);
157+
158+
return streamer.Coinbase.AdvancedTradeApi.SubscribeToTickerUpdatesAsync(name, o =>
159+
{
160+
SendStream(instrument, new()
161+
{
162+
Bid = (double)o.Data.BestBidPrice,
163+
BidSize = (double)o.Data.BestBidQuantity,
164+
Ask = (double)o.Data.BestAskPrice,
165+
AskSize = (double)o.Data.BestAskQuantity,
166+
Last = (double)((o.Data.BestBidPrice + o.Data.BestAskPrice) / 2),
167+
Time = o.DataTime?.Ticks
168+
});
169+
});
170+
}
148171
}
149172
}

Gateways/Coin/Libs/Grains/OrdersGrain.cs

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using CryptoClients.Net;
66
using CryptoClients.Net.Interfaces;
77
using CryptoExchange.Net.SharedApis;
8-
using System.Diagnostics.Metrics;
98
using System.Linq;
109
using System.Threading;
1110
using System.Threading.Tasks;
@@ -68,7 +67,7 @@ public override async Task<OrdersResponse> Orders(Criteria criteria)
6867

6968
return new()
7069
{
71-
Data = []
70+
Data = [.. spotItems, .. futureItems]
7271
};
7372
}
7473

@@ -78,7 +77,7 @@ public override async Task<OrdersResponse> Orders(Criteria criteria)
7877
/// <param name="message"></param>
7978
protected virtual Order MapSpotOrder(SharedSpotOrder message)
8079
{
81-
var instrument = new Core.Models.Instrument
80+
var instrument = new Instrument
8281
{
8382
Type = InstrumentEnum.Coins,
8483
Name = message.Symbol
@@ -87,7 +86,7 @@ protected virtual Order MapSpotOrder(SharedSpotOrder message)
8786
var action = new Operation
8887
{
8988
Id = $"{message.OrderId}",
90-
Amount = (double)message.QuantityFilled.QuantityInContracts,
89+
Amount = (double?)message.QuantityFilled.QuantityInContracts,
9190
Time = message.UpdateTime?.Ticks,
9291
Status = OrderStatusEnum.Order,
9392
Instrument = instrument
@@ -98,14 +97,19 @@ protected virtual Order MapSpotOrder(SharedSpotOrder message)
9897
Operation = action,
9998
Id = message.ClientOrderId,
10099
Type = OrderTypeEnum.Market,
101-
Amount = (double)message.OrderQuantity.QuantityInContracts,
100+
Price = (double?)message.OrderPrice,
101+
Amount = (double?)message.OrderQuantity.QuantityInContracts,
102102
Side = MapSide(message.Side)
103103
};
104104

105-
switch (message.OrderType)
105+
if (message.OrderType is SharedOrderType.Limit or SharedOrderType.LimitMaker)
106106
{
107-
case SharedOrderType.Limit:
108-
case SharedOrderType.LimitMaker: order = order with { Type = OrderTypeEnum.Limit, Price = (double)message.OrderPrice }; break;
107+
order = order with { Type = OrderTypeEnum.Limit };
108+
}
109+
110+
if (message.IsTriggerOrder is true)
111+
{
112+
order = order with { Type = OrderTypeEnum.StopLimit, Price = (double?)message.TriggerPrice };
109113
}
110114

111115
return order;
@@ -117,22 +121,17 @@ protected virtual Order MapSpotOrder(SharedSpotOrder message)
117121
/// <param name="message"></param>
118122
protected virtual Order MapFutureOrder(SharedFuturesOrder message)
119123
{
120-
var basis = new Core.Models.Instrument
121-
{
122-
Name = message.SharedSymbol.QuoteAsset,
123-
Type = InstrumentEnum.Coins
124-
};
125-
126-
var instrument = new Core.Models.Instrument
124+
var instrument = new Instrument
127125
{
128-
Type = InstrumentEnum.Coins,
126+
Leverage = (double?)message.Leverage,
127+
Type = InstrumentEnum.Futures,
129128
Name = message.Symbol
130129
};
131130

132131
var action = new Operation
133132
{
134133
Id = $"{message.OrderId}",
135-
Amount = (double)message.QuantityFilled.QuantityInContracts,
134+
Amount = (double?)message.QuantityFilled.QuantityInContracts,
136135
Time = message.UpdateTime?.Ticks,
137136
Status = OrderStatusEnum.Order,
138137
Instrument = instrument
@@ -143,14 +142,19 @@ protected virtual Order MapFutureOrder(SharedFuturesOrder message)
143142
Operation = action,
144143
Id = message.ClientOrderId,
145144
Type = OrderTypeEnum.Market,
146-
Amount = (double)message.OrderQuantity.QuantityInContracts,
145+
Price = (double?)message.OrderPrice,
146+
Amount = (double?)message.OrderQuantity.QuantityInContracts,
147147
Side = MapSide(message.Side)
148148
};
149149

150-
switch (message.OrderType)
150+
if (message.OrderType is SharedOrderType.Limit or SharedOrderType.LimitMaker)
151+
{
152+
order = order with { Type = OrderTypeEnum.Limit };
153+
}
154+
155+
if (message.IsTriggerOrder is true)
151156
{
152-
case SharedOrderType.Limit:
153-
case SharedOrderType.LimitMaker: order = order with { Type = OrderTypeEnum.Limit, Price = (double)message.OrderPrice }; break;
157+
order = order with { Type = OrderTypeEnum.StopLimit, Price = (double?)message.TriggerPrice };
154158
}
155159

156160
return order;

Gateways/Coin/Libs/Grains/PositionsGrain.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using Core.Models;
55
using CryptoClients.Net;
66
using CryptoClients.Net.Interfaces;
7+
using CryptoExchange.Net.SharedApis;
8+
using System.Linq;
79
using System.Threading;
810
using System.Threading.Tasks;
911

@@ -41,6 +43,8 @@ public virtual async Task<StatusResponse> Setup(Connection connection)
4143
state = connection;
4244
sender = new ExchangeRestClient();
4345

46+
sender.SetApiCredentials(state.Exchange, state.Token, state.Secret);
47+
4448
return new()
4549
{
4650
Data = StatusEnum.Active
@@ -53,6 +57,32 @@ public virtual async Task<StatusResponse> Setup(Connection connection)
5357
/// <param name="criteria"></param>
5458
public override async Task<OrdersResponse> Positions(Criteria criteria)
5559
{
60+
var response = new OrdersResponse();
61+
62+
switch (true)
63+
{
64+
case true when Equals(state.Exchange, sender.Coinbase.Exchange): response = await Coinbase(criteria); break;
65+
}
66+
67+
return response;
68+
}
69+
70+
/// <summary>
71+
/// Get positions from Coinbase
72+
/// </summary>
73+
/// <param name="criteria"></param>
74+
protected virtual async Task<OrdersResponse> Coinbase(Criteria criteria)
75+
{
76+
var currency = criteria.Instrument.Currency.Name;
77+
var groupsCleaner = new CancellationTokenSource(state.Timeout);
78+
var groups = await sender.Coinbase.AdvancedTradeApi.Account.GetPortfoliosAsync(null, groupsCleaner.Token);
79+
80+
foreach (var group in groups.Data)
81+
{
82+
var groupCleaner = new CancellationTokenSource(state.Timeout);
83+
var response = await sender.Coinbase.AdvancedTradeApi.Account.GetPortfolioAsync(group.Id, currency, groupCleaner.Token);
84+
}
85+
5686
return new()
5787
{
5888
Data = []

Gateways/InteractiveBrokers/Libs/Grains/ConnectionGrain.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,6 @@ await messenger.OnNextAsync(new Message()
205205
}
206206

207207
var name = this.GetDescriptor();
208-
var ordersGrain = GrainFactory.GetGrain<IOrdersGrain>(name);
209-
var positionsGrain = GrainFactory.GetGrain<IPositionsGrain>(name);
210208
var instrumentGrain = GrainFactory.GetGrain<IInstrumentGrain>(this.GetDescriptor(instrument.Name));
211209
var dataMessage = new PriceStreamMessage
212210
{

Gateways/Schwab/Libs/Grains/ConnectionGrain.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,6 @@ public override async Task<StatusResponse> Subscribe(Instrument instrument)
9494
var instrumentDescriptor = this.GetDescriptor(instrument.Name);
9595
var domGrain = GrainFactory.GetGrain<IDomGrain>(instrumentDescriptor);
9696
var instrumentGrain = GrainFactory.GetGrain<IInstrumentGrain>(instrumentDescriptor);
97-
var positionsGrain = GrainFactory.GetGrain<IPositionsGrain>(descriptor);
98-
var ordersGrain = GrainFactory.GetGrain<IOrdersGrain>(descriptor);
9997

10098
await connector.Subscribe(instrument.Name, MapSubType(instrument), async o =>
10199
{

Gateways/Schwab/Libs/Grains/OptionsGrain.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public override async Task<InstrumentsResponse> Options(Criteria criteria)
113113
/// Map instrument
114114
/// </summary>
115115
/// <param name="assetType"></param>
116-
public static InstrumentEnum? MapInstrumentType(string assetType)
116+
protected virtual InstrumentEnum? MapInstrumentType(string assetType)
117117
{
118118
switch (assetType?.ToUpper())
119119
{

Gateways/Schwab/Libs/Grains/PositionsGrain.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ protected virtual Order MapPosition(PositionMessage message)
140140
/// Convert remote position side to local
141141
/// </summary>
142142
/// <param name="message"></param>
143-
public static OrderSideEnum? MapSide(PositionMessage message)
143+
protected virtual OrderSideEnum? MapSide(PositionMessage message)
144144
{
145145
switch (true)
146146
{

Gateways/Tradier/Libs/Grains/ConnectionGrain.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,7 @@ public override async Task<StatusResponse> Subscribe(Instrument instrument)
9393
{
9494
var descriptor = this.GetDescriptor();
9595
var instrumentDescriptor = this.GetDescriptor(instrument.Name);
96-
var domGrain = GrainFactory.GetGrain<IDomGrain>(instrumentDescriptor);
9796
var instrumentGrain = GrainFactory.GetGrain<IInstrumentGrain>(instrumentDescriptor);
98-
var positionsGrain = GrainFactory.GetGrain<IPositionsGrain>(descriptor);
99-
var ordersGrain = GrainFactory.GetGrain<IOrdersGrain>(descriptor);
10097

10198
connector.OnPrice += async o =>
10299
{

0 commit comments

Comments
 (0)