Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f20a020fd |
No files matched your search
@@ -1,11 +1,13 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Spark.Api.MarketData {
|
||||
namespace Spark.Api.MarketData
|
||||
{
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.core;
|
||||
using bts.api.synthetic;
|
||||
using bts.spark;
|
||||
using bts.utils;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Reactive;
|
||||
@@ -13,7 +15,8 @@ namespace Spark.Api.MarketData {
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class SyntheticSecurityClient : IDisposable {
|
||||
public class SyntheticSecurityClient : IDisposable
|
||||
{
|
||||
readonly SyntheticSecurityService _synth_service;
|
||||
readonly IObservable<TableUpdate<MetadataImmutable, uint>> _synthetic_metadata;
|
||||
readonly IObservable<TableUpdate<SecurityImmutable, uint>> _securities;
|
||||
@@ -21,7 +24,8 @@ namespace Spark.Api.MarketData {
|
||||
|
||||
public SyntheticSecurityClient(
|
||||
SyntheticSecurityService synth_service,
|
||||
IObservable<TableUpdate<SecurityImmutable, uint>> securities) {
|
||||
IObservable<TableUpdate<SecurityImmutable, uint>> securities)
|
||||
{
|
||||
_synth_service = synth_service;
|
||||
_securities = securities;
|
||||
var bootstraps = new DisposableBuilder();
|
||||
@@ -39,16 +43,50 @@ namespace Spark.Api.MarketData {
|
||||
(sec, id) => new SyntheticSecurityTuple(sec, sec.Synthetic.Name, null),
|
||||
stup => stup.security.Id);
|
||||
|
||||
public async Task<uint> create_synthetic_security(SecurityImmutable security) {
|
||||
public async Task<uint> create_synthetic_security(SecurityImmutable security)
|
||||
{
|
||||
var res = await _synth_service.create_synthetic_async(security.CloneToMutable());
|
||||
if (!res.success) {
|
||||
if (!res.success)
|
||||
{
|
||||
throw new ApiException(res.error_message);
|
||||
}
|
||||
return res.value.Error switch {
|
||||
return res.value.Error switch
|
||||
{
|
||||
CreateResult.Types.Error.Ok => res.value.Key,
|
||||
_ => throw new ApiException(res.value.Error.ToString())
|
||||
};
|
||||
}
|
||||
public async Task<bts.api.orderman.Response> try_create_synthetic_security(SecurityImmutable security)
|
||||
{
|
||||
try
|
||||
{
|
||||
var v = await create_synthetic_security(security);
|
||||
var r = new bts.api.orderman.Response
|
||||
{
|
||||
OrderKey = v,
|
||||
ErrorCode = bts.api.orderman.OrderError.Ok
|
||||
};
|
||||
return r;
|
||||
}
|
||||
catch (ApiException e)
|
||||
{
|
||||
var r = new bts.api.orderman.Response
|
||||
{
|
||||
ErrorCode = bts.api.orderman.OrderError.Undefined,
|
||||
Msg = e.Message
|
||||
};
|
||||
return r;
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
var r = new bts.api.orderman.Response
|
||||
{
|
||||
ErrorCode = bts.api.orderman.OrderError.Undefined
|
||||
};
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the execution strategy for a synthetic security
|
||||
@@ -57,16 +95,20 @@ namespace Spark.Api.MarketData {
|
||||
/// <param name="strategy">The new execution strategy</param>
|
||||
/// <returns>The error message of the operation (null if it was successful)</returns>
|
||||
public async Task<string?> update_synthetic_strategy(
|
||||
uint synth_sec_id, ExecutionStrategyImmutable strategy) {
|
||||
uint synth_sec_id, ExecutionStrategyImmutable strategy)
|
||||
{
|
||||
var res = await _synth_service.update_security_metadata_async(
|
||||
new Metadata() {
|
||||
new Metadata()
|
||||
{
|
||||
SecurityKey = synth_sec_id,
|
||||
Strategy = strategy.CloneToMutable()
|
||||
});
|
||||
if (!res.success) {
|
||||
if (!res.success)
|
||||
{
|
||||
return res.error_message;
|
||||
}
|
||||
return res.value.Error switch {
|
||||
return res.value.Error switch
|
||||
{
|
||||
UpdateResult.Types.Error.Ok => null,
|
||||
_ => res.value.Error.ToString()
|
||||
};
|
||||
|
||||
@@ -270,6 +270,18 @@ namespace bts.websocket_core {
|
||||
handle_update_order(req);
|
||||
break;
|
||||
}
|
||||
case WebsocketRequest.REQUEST_TYPES.CREATE_SYNTHETIC: {
|
||||
handle_create_synthetic(req);
|
||||
break;
|
||||
}
|
||||
case WebsocketRequest.REQUEST_TYPES.DELETE_SYNTHETIC: {
|
||||
// handle_delete_order(req);
|
||||
break;
|
||||
}
|
||||
case WebsocketRequest.REQUEST_TYPES.UPDATE_SYNTHETIC: {
|
||||
// handle_update_order(req);
|
||||
break;
|
||||
}
|
||||
case WebsocketRequest.REQUEST_TYPES.UNKOWN: {
|
||||
///send error
|
||||
break;
|
||||
@@ -308,6 +320,14 @@ namespace bts.websocket_core {
|
||||
}
|
||||
handle_correct_request(req.id, status, null, req.client_id);
|
||||
}
|
||||
public async void handle_create_synthetic(WebsocketRequest req) {
|
||||
(bool suc, uint? id, string status) = await WebsocketRestHandler.CreateSyntheticAsync(req, Synth_Sec_Client, _securities);
|
||||
if (!suc) {
|
||||
handle_incorrect_request(req, status);
|
||||
return;
|
||||
}
|
||||
handle_correct_request(req.id, status, new { order_key = id }, req.client_id);
|
||||
}
|
||||
public void handle_subscription(WebsocketRequest req) {
|
||||
WebsocketSubscriptionHandler? hdlr;
|
||||
string status;
|
||||
|
||||
@@ -12,8 +12,10 @@ namespace bts.websocket_core {
|
||||
UNSUBSCRIBE,
|
||||
ENTER_ORDER,
|
||||
DELETE_ORDER,
|
||||
|
||||
UPDATE_ORDER,
|
||||
CREATE_SYNTHETIC,
|
||||
DELETE_SYNTHETIC,
|
||||
UPDATE_SYNTHETIC,
|
||||
DELETE,
|
||||
PATCH,
|
||||
UNKOWN = 0
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace bts.websocket_core {
|
||||
using bts.api.admin;
|
||||
using bts.api.core;
|
||||
using bts.api.orderman;
|
||||
using bts.api.synthetic;
|
||||
|
||||
using mbts;
|
||||
|
||||
@@ -124,6 +125,45 @@ namespace bts.websocket_core {
|
||||
};
|
||||
return (true, customdef, status);
|
||||
}
|
||||
private async static Task<(bool, SecurityImmutable?, string)> TryGetSecDefAsync(WebsocketRequest req, IReadOnlyDictionary<uint, SecurityMD> securities) {
|
||||
string status = "";
|
||||
if (!WebsocketJsonParsers.TryParse(
|
||||
req.parameters,
|
||||
"name",
|
||||
out WebsocketJsonParsers.StringWrapper? name,
|
||||
out status)
|
||||
|| name == null) {
|
||||
return (false, null, status);
|
||||
}
|
||||
|
||||
Result<AdminData> adminResult = await _admin.Value.get_admin_data_async(new VoidMessage());
|
||||
Security sec = new() {
|
||||
Exchange = Venue.Bts,
|
||||
Symbol = securities.FirstOrDefault(
|
||||
x => x.Value.id != 0).Value.security.Symbol,
|
||||
Synthetic = new() {
|
||||
Name = name.Value.Val
|
||||
}
|
||||
};
|
||||
sec.Synthetic.Legs.AddRange(new[]{
|
||||
new ContractLeg(){
|
||||
Quantity = 1,
|
||||
Side = Side.Buy,
|
||||
PriceMultiplier = 1,
|
||||
Security = securities.FirstOrDefault(
|
||||
x => x.Value.security.HasDeribit).Value.security.CloneToMutable()
|
||||
}, new ContractLeg(){
|
||||
Quantity = 1,
|
||||
Side = Side.Buy,
|
||||
PriceMultiplier = -1,
|
||||
Security = securities.FirstOrDefault(
|
||||
x => x.Value.security.HasDeribit && x.Value.security.Id != 28).Value.security.CloneToMutable()
|
||||
}
|
||||
});
|
||||
var s = new SecurityImmutable(sec);
|
||||
return (true, s, "");
|
||||
}
|
||||
private static (bool,SecurityMD?, string) TryGetSecMD(,)
|
||||
private async static Task<(bool, OrderDefinition?, string)> TryGetOrderDefAsync(WebsocketRequest req, IReadOnlyDictionary<uint, SecurityMD> securities) {
|
||||
if (req.parameters == null) {
|
||||
return (false, null, "parameters not present");
|
||||
@@ -235,17 +275,24 @@ namespace bts.websocket_core {
|
||||
}
|
||||
public static async Task<(bool success, uint? orderId, string status)> EnterOrderAsync(
|
||||
WebsocketRequest request, OrdersClient ordersClient, IReadOnlyDictionary<uint, SecurityMD> securities) {
|
||||
double? quantity = null;
|
||||
double? price = null;
|
||||
OrderDefinition? orderDefinition = null;
|
||||
uint? orderId = null;
|
||||
string status = string.Empty;
|
||||
|
||||
if (!WebsocketJsonParsers.TryParse(request.parameters, "quantity", out quantity, out status) || quantity == null) {
|
||||
|
||||
if (!WebsocketJsonParsers.TryParse(
|
||||
request.parameters,
|
||||
"quantity",
|
||||
out double? quantity,
|
||||
out status)
|
||||
|| quantity == null) {
|
||||
return (false, null, status);
|
||||
}
|
||||
|
||||
if (!WebsocketJsonParsers.TryParse(request.parameters, "price", out price, out status) || price == null) {
|
||||
if (!WebsocketJsonParsers.TryParse(
|
||||
request.parameters,
|
||||
"price",
|
||||
out double? price,
|
||||
out status)
|
||||
|| price == null) {
|
||||
return (false, null, status);
|
||||
}
|
||||
|
||||
@@ -265,5 +312,22 @@ namespace bts.websocket_core {
|
||||
|
||||
return (true, orderId, status);
|
||||
}
|
||||
public static async Task<(bool success, uint? orderId, string status)> CreateSyntheticAsync(
|
||||
WebsocketRequest request, Spark.Api.MarketData.SyntheticSecurityClient synthSecClient, IReadOnlyDictionary<uint, SecurityMD> securities) {
|
||||
SecurityImmutable? secDefinition = null;
|
||||
string status = string.Empty;
|
||||
(bool success, secDefinition, status) = await TryGetSecDefAsync(request, securities);
|
||||
if (!success || secDefinition == null) {
|
||||
return (success, null, status);
|
||||
}
|
||||
var result = await synthSecClient.try_create_synthetic_security(security: (SecurityImmutable)secDefinition);
|
||||
if (result.ErrorCode != OrderError.Ok) {
|
||||
return (false, null, result.ErrorCode.ToString() + " " + result.Msg);
|
||||
}
|
||||
|
||||
status = result.ErrorCode.ToString();
|
||||
|
||||
return (true, result.OrderKey, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,12 @@ using System.Reflection;
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
namespace bts.websocket_core {
|
||||
namespace bts.websocket_core
|
||||
{
|
||||
// Placeholder for whatever is needed for the server to start
|
||||
// listening to clients (port, security etc)
|
||||
public class WebsocketServerParams {
|
||||
public class WebsocketServerParams
|
||||
{
|
||||
public string Port { get; }
|
||||
public string Host { get; }
|
||||
public string Scheme { get; }
|
||||
@@ -15,17 +17,20 @@ namespace bts.websocket_core {
|
||||
public double Keep_alive_interval_seconds { get; }
|
||||
public string Uri { get; }
|
||||
|
||||
public WebsocketServerParams() {
|
||||
public WebsocketServerParams()
|
||||
{
|
||||
//will later do this from conf file
|
||||
this.Default_end_point = "/";
|
||||
this.Host = "titan";
|
||||
this.Host = "localhost";
|
||||
this.Scheme = "http";
|
||||
this.Port = "8080";
|
||||
this.Keep_alive_interval_seconds = 0.1;
|
||||
this.Uri = this.Scheme + "://" + this.Host + ":" + this.Port; ;
|
||||
}
|
||||
public WebSocketOptions get_ws_options() {
|
||||
return new WebSocketOptions() {
|
||||
public WebSocketOptions get_ws_options()
|
||||
{
|
||||
return new WebSocketOptions()
|
||||
{
|
||||
KeepAliveInterval = TimeSpan.FromSeconds(this.Keep_alive_interval_seconds)
|
||||
};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user