Skip to content

Commit

Permalink
Merge pull request #19 from fbridger/feature/Remove-ServiceStack
Browse files Browse the repository at this point in the history
Remove service stack dependency
  • Loading branch information
naicigam authored Oct 25, 2021
2 parents a2494a0 + 155fb7c commit b85dcf0
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 107 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto
16 changes: 14 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
/git/.vs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

/.vs
/git/.vs
/.vs/Primary
/packages
/Primary/bin
Expand All @@ -8,4 +21,3 @@
/Primary.Tests/bin
/Primary.Tests/obj
*.user
/codealike.json
197 changes: 96 additions & 101 deletions Primary/Api.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
using System;
using Newtonsoft.Json;
using Primary.Data;
using Primary.Data.Orders;
using Primary.WebSockets;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Primary.Data;
using Primary.Data.Orders;
using Primary.WebSockets;
using ServiceStack;
using System.Web;

namespace Primary
{
Expand All @@ -19,16 +21,18 @@ public class Api
/// <summary>This is the default demo endpoint.</summary>
/// <remarks>You can get a demo username at https://remarkets.primary.ventures.</remarks>
public static Uri DemoEndpoint => new Uri("https://api.remarkets.primary.com.ar");

/// <summary>
/// Build a new API object.
/// </summary>
public Api(Uri baseUri)
public Api(Uri baseUri, HttpClient httpClient = null)
{
BaseUri = baseUri;
HttpClient = httpClient ?? new HttpClient();
}

public Uri BaseUri { get; private set; }
public HttpClient HttpClient { get; private set; }

#region Login

Expand All @@ -40,27 +44,30 @@ public Api(Uri baseUri)
/// <param name="username">User used for authentication.</param>
/// <param name="password">Password used for authentication.</param>
/// <returns></returns>
public async Task Login(string username, string password)
public async Task<bool> Login(string username, string password)
{
var uri = new Uri(BaseUri, "/auth/getToken");

await uri.ToString().PostToUrlAsync(null, "*/*",
request =>
{
request.Headers.Add("X-Username", username);
request.Headers.Add("X-Password", password);
},
response =>
{
AccessToken = response.Headers["X-Auth-Token"];
}
);

HttpClient.DefaultRequestHeaders.Clear();
HttpClient.DefaultRequestHeaders.Add("X-Username", username);
HttpClient.DefaultRequestHeaders.Add("X-Password", password);

var result = await HttpClient.PostAsync(uri, new StringContent(string.Empty));

if (result.IsSuccessStatusCode)
{
AccessToken = result.Headers.GetValues("X-Auth-Token").FirstOrDefault();
HttpClient.DefaultRequestHeaders.Clear();
HttpClient.DefaultRequestHeaders.Add("X-Auth-Token", AccessToken);
}

return result.IsSuccessStatusCode;
}

public const string DemoUsername = "naicigam2046";
public const string DemoPassword = "nczhmL9@";
public const string DemoAccount = "REM2046";

#endregion

#region Instruments information
Expand All @@ -69,14 +76,11 @@ await uri.ToString().PostToUrlAsync(null, "*/*",
/// Get all instruments currently traded on the exchange.
/// </summary>
/// <returns>Instruments information.</returns>
public async Task< IEnumerable<Instrument> > GetAllInstruments()
public async Task<IEnumerable<Instrument>> GetAllInstruments()
{
var uri = new Uri(BaseUri, "/rest/instruments/all");
var response = await uri.ToString().GetJsonFromUrlAsync( request =>
{
request.Headers.Add("X-Auth-Token", AccessToken);
});

var response = await HttpClient.GetStringAsync(uri);

var data = JsonConvert.DeserializeObject<GetAllInstrumentsResponse>(response);
return data.Instruments.Select(i => i.InstrumentId);
}
Expand All @@ -96,37 +100,35 @@ public class InstrumentEntry
#endregion

#region Historical data

/// <summary>
/// Get historical trades for a specific instrument.
/// </summary>
/// <param name="instrument">Instrument to get information for.</param>
/// <param name="dateFrom">First date of trading information.</param>
/// <param name="dateTo">Last date of trading information.</param>
/// <returns>Trade information for the instrument in the specified period.</returns>
public async Task< IEnumerable<Trade> > GetHistoricalTrades(Instrument instrument,
DateTime dateFrom,
public async Task<IEnumerable<Trade>> GetHistoricalTrades(Instrument instrument,
DateTime dateFrom,
DateTime dateTo)
{
var uri = new Uri(BaseUri, "/rest/data/getTrades");

var jsonResponse = await uri.ToString()
.AddQueryParam("marketId", instrument.Market)
.AddQueryParam("symbol", instrument.Symbol)
.AddQueryParam("dateFrom", dateFrom.ToString("yyyy-MM-dd"))
.AddQueryParam("dateTo", dateTo.ToString("yyyy-MM-dd"))
.GetJsonFromUrlAsync( request =>
{
request.Headers.Add("X-Auth-Token", AccessToken);
});

var response = JsonConvert.DeserializeObject<GetTradesResponse>(jsonResponse);
if (response.Status == Status.Error)
UriBuilder builder = new UriBuilder(BaseUri + "/rest/data/getTrades");
var query = HttpUtility.ParseQueryString(builder.Query);
query["marketId"] = instrument.Market;
query["symbol"] = instrument.Symbol;
query["dateFrom"] = dateFrom.ToString("yyyy-MM-dd");
query["dateTo"] = dateTo.ToString("yyyy-MM-dd");
builder.Query = query.ToString();

var response = await HttpClient.GetStringAsync(builder.Uri);
var data = JsonConvert.DeserializeObject<GetTradesResponse>(response);

if (data.Status == Status.Error)
{
throw new Exception($"{response.Message} ({response.Description})");
throw new Exception($"{data.Message} ({data.Description})");
}

return response.Trades;
return data.Trades;
}

private class GetTradesResponse
Expand All @@ -145,7 +147,7 @@ private class GetTradesResponse
}

#endregion

#region Market data sockets

/// <summary>
Expand All @@ -156,12 +158,12 @@ private class GetTradesResponse
/// <param name="level"></param>
/// <param name="depth">Depth of the book.</param>
/// <returns>The market data web socket.</returns>
public MarketDataWebSocket CreateMarketDataSocket(IEnumerable<Instrument> instruments,
public MarketDataWebSocket CreateMarketDataSocket(IEnumerable<Instrument> instruments,
IEnumerable<Entry> entries,
uint level, uint depth
)
{
return CreateMarketDataSocket( instruments, entries, level, depth, new CancellationToken() );
return CreateMarketDataSocket(instruments, entries, level, depth, new CancellationToken());
}

/// <summary>
Expand All @@ -182,7 +184,7 @@ public MarketDataWebSocket CreateMarketDataSocket(IEnumerable<Instrument> instru
/// <param name="depth">Depth of the book.</param>
/// <param name="cancellationToken">Custom cancellation token to end the socket task.</param>
/// <returns>The market data web socket.</returns>
public MarketDataWebSocket CreateMarketDataSocket(IEnumerable<Instrument> instruments,
public MarketDataWebSocket CreateMarketDataSocket(IEnumerable<Instrument> instruments,
IEnumerable<Entry> entries,
uint level, uint depth,
CancellationToken cancellationToken
Expand Down Expand Up @@ -210,7 +212,7 @@ CancellationToken cancellationToken
/// <returns>The order data web socket.</returns>
public OrderDataWebSocket CreateOrderDataSocket(IEnumerable<string> accounts)
{
return CreateOrderDataSocket( accounts, new CancellationToken() );
return CreateOrderDataSocket(accounts, new CancellationToken());
}

/// <summary>
Expand All @@ -225,7 +227,7 @@ CancellationToken cancellationToken
{
var request = new OrderDataRequest
{
Accounts = accounts.Select(a => new OrderStatus.AccountId() { Id = a } ).ToArray()
Accounts = accounts.Select(a => new OrderStatus.AccountId() { Id = a }).ToArray()
};

return new OrderDataWebSocket(this, request, cancellationToken);
Expand All @@ -243,62 +245,56 @@ CancellationToken cancellationToken
/// <returns>Order identifier.</returns>
public async Task<OrderId> SubmitOrder(string account, Order order)
{
var uri = new Uri(BaseUri, "/rest/order/newSingleOrder").ToString();

uri = uri.AddQueryParam("marketId", "ROFX")
.AddQueryParam("symbol", order.Instrument.Symbol)
.AddQueryParam("price", order.Price)
.AddQueryParam("orderQty", order.Quantity)
.AddQueryParam("ordType", order.Type.ToApiString())
.AddQueryParam("side", order.Side.ToApiString())
.AddQueryParam("timeInForce", order.Expiration.ToApiString())
.AddQueryParam("account", account)
.AddQueryParam("cancelPrevious", order.CancelPrevious)
.AddQueryParam("iceberg", order.Iceberg)
.AddQueryParam("expireDate", order.ExpirationDate.ToString("yyyyMMdd"));
var builder = new UriBuilder(BaseUri + "/rest/order/newSingleOrder");
var query = HttpUtility.ParseQueryString(builder.Query);
query["marketId"] = "ROFX";
query["symbol"] = order.Instrument.Symbol;
query["price"] = order.Price?.ToString(CultureInfo.InvariantCulture);
query["orderQty"] = order.Quantity.ToString();
query["ordType"] = order.Type.ToApiString();
query["side"] = order.Side.ToApiString();
query["timeInForce"] = order.Expiration.ToApiString();
query["account"] = account;
query["cancelPrevious"] = order.CancelPrevious.ToString(CultureInfo.InvariantCulture);
query["iceberg"] = order.Iceberg.ToString(CultureInfo.InvariantCulture);
query["expireDate"] = order.ExpirationDate.ToString("yyyyMMdd");

if (order.Iceberg)
{
uri = uri.AddQueryParam("displayQty", order.DisplayQuantity);
query["displayQty"] = order.DisplayQuantity.ToString(CultureInfo.InvariantCulture);
}

var jsonResponse = await uri.GetJsonFromUrlAsync(
request =>
{
request.Headers.Add("X-Auth-Token", AccessToken);
}
);

builder.Query = query.ToString();

var jsonResponse = await HttpClient.GetStringAsync(builder.Uri);

var response = JsonConvert.DeserializeObject<OrderIdResponse>(jsonResponse);
if (response.Status == Status.Error)
{
throw new Exception($"{response.Message} ({response.Description})");
}

return new OrderId()
{
{
ClientOrderId = response.Order.ClientId,
Proprietary = response.Order.Proprietary
};
}

/// <summary>
/// Get order information from identifier.
/// </summary>
/// <param name="orderId">Order identifier.</param>
/// <returns>Order information.</returns>
public async Task<OrderStatus> GetOrderStatus(OrderId orderId)
{
var uri = new Uri(BaseUri, "/rest/order/id").ToString();
uri = uri.AddQueryParam("clOrdId", orderId.ClientOrderId)
.AddQueryParam("proprietary", orderId.Proprietary);

var jsonResponse = await uri.GetJsonFromUrlAsync(
request =>
{
request.Headers.Add("X-Auth-Token", AccessToken);
}
);
var builder = new UriBuilder(BaseUri + "/rest/order/id");
var query = HttpUtility.ParseQueryString(builder.Query);
query["clOrdId"] = orderId.ClientOrderId;
query["proprietary"] = orderId.Proprietary;
builder.Query = query.ToString();

var jsonResponse = await HttpClient.GetStringAsync(builder.Uri);

var response = JsonConvert.DeserializeObject<GetOrderResponse>(jsonResponse);
if (response.Status == Status.Error)
Expand All @@ -315,16 +311,15 @@ public async Task<OrderStatus> GetOrderStatus(OrderId orderId)
/// <param name="orderId">Order identifier to cancel.</param>
public async Task CancelOrder(OrderId orderId)
{
var uri = new Uri(BaseUri, "/rest/order/cancelById").ToString();
uri = uri.AddQueryParam("clOrdId", orderId.ClientOrderId)
.AddQueryParam("proprietary", orderId.Proprietary);

var jsonResponse = await uri.GetJsonFromUrlAsync(
request =>
{
request.Headers.Add("X-Auth-Token", AccessToken);
}
);

var builder = new UriBuilder(BaseUri + "/rest/order/cancelById");
var query = HttpUtility.ParseQueryString(builder.Query);
query["clOrdId"] = orderId.ClientOrderId;
query["proprietary"] = orderId.Proprietary;
builder.Query = query.ToString();

var jsonResponse = await HttpClient.GetStringAsync(builder.Uri);

var response = JsonConvert.DeserializeObject<OrderIdResponse>(jsonResponse);
//if (response.Status == Status.Error)
//{
Expand All @@ -336,15 +331,15 @@ private struct OrderIdResponse
{
[JsonProperty("status")]
public string Status;

[JsonProperty("message")]
public string Message;

[JsonProperty("description")]
public string Description;

public struct Id
{
{
[JsonProperty("clientId")]
public string ClientId { get; set; }

Expand All @@ -360,7 +355,7 @@ private struct GetOrderResponse
{
[JsonProperty("status")]
public string Status;

[JsonProperty("message")]
public string Message;

Expand Down
1 change: 1 addition & 0 deletions Primary/Data/Orders/Enums.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Newtonsoft.Json;
using Primary.Serialization;
using System.Globalization;

namespace Primary.Data.Orders
{
Expand Down
Loading

0 comments on commit b85dcf0

Please sign in to comment.