Compare commits

...
Author SHA1 Message Date
arhamGIT 0f20a020fd spreaeder not working 2023-09-19 11:16:10 -04:00
5 changed files with 156 additions and 23 deletions

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)
};
}