diff --git a/Insight.Tinkoff.Invest.Tests/Base/TestBase.cs b/Insight.Tinkoff.Invest.Tests/Base/TestBase.cs index b8dad25..9c4df5e 100644 --- a/Insight.Tinkoff.Invest.Tests/Base/TestBase.cs +++ b/Insight.Tinkoff.Invest.Tests/Base/TestBase.cs @@ -12,7 +12,7 @@ public class TestBase public TestBase() { Token = TestConfigurationManager.GetToken(); - RestConfiguration = new TinkoffRestServiceConfiguration + RestConfiguration = new RestConfiguration { AccessToken = Token }; @@ -20,7 +20,7 @@ public TestBase() protected string Token { get; } - protected TinkoffRestServiceConfiguration RestConfiguration { get; } + protected RestConfiguration RestConfiguration { get; } protected void ValidateRestResponse(ResponseBase response) { @@ -35,7 +35,7 @@ private static class TestConfigurationManager public static string GetToken() { - return _config.Value["Token"]?.ToString(); + return _config.Value["AccessToken"]?.ToString(); } } } diff --git a/Insight.Tinkoff.Invest.Tests/OperationsTest.cs b/Insight.Tinkoff.Invest.Tests/OperationsTest.cs index b0baf8e..8816a03 100644 --- a/Insight.Tinkoff.Invest.Tests/OperationsTest.cs +++ b/Insight.Tinkoff.Invest.Tests/OperationsTest.cs @@ -1,3 +1,4 @@ +using System; using System.Threading; using System.Threading.Tasks; using Insight.Tinkoff.Invest.Domain; @@ -23,9 +24,11 @@ public async Task Should_get_operations() { var filter = new OperationsFilter { + From = DateTime.Now - TimeSpan.FromDays(30), + To = DateTime.Now, // Accenture Figi = "BBG000D9D830", - Interval = OperationInterval.Day + Interval = OperationInterval.Month }; var response = await _operationService.Get(filter, CancellationToken.None); diff --git a/Insight.Tinkoff.Invest.Tests/OrderTest.cs b/Insight.Tinkoff.Invest.Tests/OrderTest.cs index 0de7a3f..37d559a 100644 --- a/Insight.Tinkoff.Invest.Tests/OrderTest.cs +++ b/Insight.Tinkoff.Invest.Tests/OrderTest.cs @@ -29,7 +29,7 @@ public async Task Should_get_orders() } [Fact] - public async Task Should_post_limit_order() + public async Task Should_place_limit_order() { var balanceSetResponse = await _sandboxService.SetCurrencyBalance(new SandboxSetCurrencyBalanceRequest { @@ -39,14 +39,14 @@ public async Task Should_post_limit_order() ValidateRestResponse(balanceSetResponse); - var request = new LimitOrderRequest + var request = new PlaceLimitOrderRequest { Lots = 1, Operation = OperationType.Buy, Price = 180 }; - var response = await _orderService.PostLimitOrder("BBG000D9D830", request, CancellationToken.None); + var response = await _orderService.PlaceLimitOrder("BBG000D9D830", request, CancellationToken.None); ValidateRestResponse(response); Assert.NotNull(response.Order); diff --git a/Insight.Tinkoff.Invest.Tests/StreamServiceTest.cs b/Insight.Tinkoff.Invest.Tests/StreamServiceTest.cs index fb7a517..b6f749b 100644 --- a/Insight.Tinkoff.Invest.Tests/StreamServiceTest.cs +++ b/Insight.Tinkoff.Invest.Tests/StreamServiceTest.cs @@ -3,10 +3,12 @@ using System.Threading.Tasks; using Insight.Tinkoff.Invest.Domain; using Insight.Tinkoff.Invest.Dto.Messages; +using Insight.Tinkoff.Invest.Dto.Payloads; using Insight.Tinkoff.Invest.Infrastructure.Configurations; using Insight.Tinkoff.Invest.Infrastructure.Extensions; using Insight.Tinkoff.Invest.Services; using Insight.Tinkoff.Invest.Tests.Base; +using Newtonsoft.Json; using Xunit; using Xunit.Abstractions; @@ -20,9 +22,9 @@ public sealed class StreamServiceTest : TestBase public StreamServiceTest(ITestOutputHelper testOutputHelper) { _testOutputHelper = testOutputHelper; - _streamService = new StreamMarketService(new StreamMarketServiceConfiguration + _streamService = new StreamMarketService(new StreamConfiguration { - Token = Token + AccessToken = Token }); } @@ -34,24 +36,32 @@ public async Task Should_receive_messages_from_as_observable() .Do(x => { Assert.NotNull(x); - Assert.Equal("orderbook", x.Event, StringComparer.OrdinalIgnoreCase); switch (x) { case OrderBookMessage m: + Assert.Equal("orderbook", x.Event, StringComparer.OrdinalIgnoreCase); _testOutputHelper.WriteLine( - $"[{DateTime.Now:HH:mm:ss.fff}]: type: {m.Event}, figi: {m.Payload.Figi}"); + $"[{DateTime.Now:HH:mm:ss.fff}]: {JsonConvert.SerializeObject(m)}\n"); + break; + case InstrumentInfoMessage m: + Assert.Equal("instrument_info", x.Event, StringComparer.OrdinalIgnoreCase); + _testOutputHelper.WriteLine( + $"[{DateTime.Now:HH:mm:ss.fff}]: {JsonConvert.SerializeObject(m)}\n"); + break; + case CandleMessage m: + Assert.Equal("candle", x.Event, StringComparer.OrdinalIgnoreCase); + _testOutputHelper.WriteLine( + $"[{DateTime.Now:HH:mm:ss.fff}]: {JsonConvert.SerializeObject(m)}\n"); break; default: throw new ArgumentException(nameof(x)); } }, ex => { throw ex; }) .Subscribe(); - - await _streamService.Send(new SubscribeOrderBookMessage - { - Figi = "BBG000D9D830", - Depth = 5 - }); + + await _streamService.Send(new SubscribeOrderBookMessage("BBG000D9D830", 5)); + await _streamService.Send(new SubscribeInstrumentInfoMessage("BBG000D9D830")); + await _streamService.Send(new SubscribeCandleMessage("BBG000D9D830", CandleInterval.Minute)); await Task.Delay(5 * 1000); } diff --git a/Insight.Tinkoff.Invest.Tests/appsettings.json b/Insight.Tinkoff.Invest.Tests/appsettings.json index dfd396d..de91e52 100644 --- a/Insight.Tinkoff.Invest.Tests/appsettings.json +++ b/Insight.Tinkoff.Invest.Tests/appsettings.json @@ -1,3 +1,3 @@ { - "Token": "" + "AccessToken": "" } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Domain/Services/IOrderService.cs b/Insight.Tinkoff.Invest/Domain/Services/IOrderService.cs index b50b33d..ae1d52b 100644 --- a/Insight.Tinkoff.Invest/Domain/Services/IOrderService.cs +++ b/Insight.Tinkoff.Invest/Domain/Services/IOrderService.cs @@ -12,6 +12,6 @@ public interface IOrderService Task Get(CancellationToken cancellationToken = default); - Task PostLimitOrder(string figi, LimitOrderRequest request, CancellationToken cancellationToken = default); + Task PlaceLimitOrder(string figi, PlaceLimitOrderRequest request, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Dto/Operations/ExtendedOperationType.cs b/Insight.Tinkoff.Invest/Dto/Operations/ExtendedOperationType.cs index ca78a57..115d424 100644 --- a/Insight.Tinkoff.Invest/Dto/Operations/ExtendedOperationType.cs +++ b/Insight.Tinkoff.Invest/Dto/Operations/ExtendedOperationType.cs @@ -6,11 +6,26 @@ namespace Insight.Tinkoff.Invest.Dto [JsonConverter(typeof(StringEnumConverter))] public enum ExtendedOperationType { + BuyCard, Buy, Sell, BrokerCommission, ExchangeCommission, ServiceCommission, - MarginCommission + MarginCommission, + OtherCommission, + PayIn, + PayOut, + Tax, + TaxLucre, + TaxDividend, + TaxCoupon, + TaxBack, + Repayment, + PartRepayment, + Coupon, + Dividend, + SecurityIn, + SecurityOut } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Dto/Orders/Order.cs b/Insight.Tinkoff.Invest/Dto/Orders/Order.cs index 03ca04d..8ee1c3a 100644 --- a/Insight.Tinkoff.Invest/Dto/Orders/Order.cs +++ b/Insight.Tinkoff.Invest/Dto/Orders/Order.cs @@ -8,15 +8,8 @@ public sealed class Order public string Figi { get; set; } - /// - /// operation type - /// - [JsonProperty("operation")] - public OperationType OperationType { get; set; } - - /// - /// OrderStatus - /// + public OperationType Operation { get; set; } + public OrderStatus Status { get; set; } public int RequestedLots { get; set; } diff --git a/Insight.Tinkoff.Invest/Dto/Orders/LimitOrderRequest.cs b/Insight.Tinkoff.Invest/Dto/Orders/PlaceLimitOrderRequest.cs similarity index 80% rename from Insight.Tinkoff.Invest/Dto/Orders/LimitOrderRequest.cs rename to Insight.Tinkoff.Invest/Dto/Orders/PlaceLimitOrderRequest.cs index d3ee692..aef4607 100644 --- a/Insight.Tinkoff.Invest/Dto/Orders/LimitOrderRequest.cs +++ b/Insight.Tinkoff.Invest/Dto/Orders/PlaceLimitOrderRequest.cs @@ -1,6 +1,6 @@ namespace Insight.Tinkoff.Invest.Dto { - public sealed class LimitOrderRequest + public sealed class PlaceLimitOrderRequest { public int Lots { get; set; } diff --git a/Insight.Tinkoff.Invest/Dto/Orders/PlacedLimitOrder.cs b/Insight.Tinkoff.Invest/Dto/Orders/PlacedLimitOrder.cs index 8815744..438aeac 100644 --- a/Insight.Tinkoff.Invest/Dto/Orders/PlacedLimitOrder.cs +++ b/Insight.Tinkoff.Invest/Dto/Orders/PlacedLimitOrder.cs @@ -3,11 +3,10 @@ namespace Insight.Tinkoff.Invest.Dto { public sealed class PlacedLimitOrder - { + { public string OrderId { get; set; } - [JsonProperty("operation")] - public OperationType OperationType { get; set; } + public OperationType Operation { get; set; } public OrderStatus Status { get; set; } diff --git a/Insight.Tinkoff.Invest/Dto/Orders/Responses/LimitOrderResponse.cs b/Insight.Tinkoff.Invest/Dto/Orders/Responses/LimitOrderResponse.cs index ef380c0..4f7865c 100644 --- a/Insight.Tinkoff.Invest/Dto/Orders/Responses/LimitOrderResponse.cs +++ b/Insight.Tinkoff.Invest/Dto/Orders/Responses/LimitOrderResponse.cs @@ -5,8 +5,9 @@ namespace Insight.Tinkoff.Invest.Dto.Responses { public sealed class LimitOrderResponse : ResponseBase { + [JsonProperty] public PlacedLimitOrder Order { get; } - + [JsonConstructor] public LimitOrderResponse([JsonProperty("payload")] PlacedLimitOrder limitOrder) { diff --git a/Insight.Tinkoff.Invest/Dto/Orders/Responses/OrdersResponse.cs b/Insight.Tinkoff.Invest/Dto/Orders/Responses/OrdersResponse.cs index d272544..e53bee5 100644 --- a/Insight.Tinkoff.Invest/Dto/Orders/Responses/OrdersResponse.cs +++ b/Insight.Tinkoff.Invest/Dto/Orders/Responses/OrdersResponse.cs @@ -6,6 +6,7 @@ namespace Insight.Tinkoff.Invest.Dto.Responses { public sealed class OrdersResponse : ResponseBase { + [JsonProperty] public IReadOnlyCollection Orders { get; } [JsonConstructor] diff --git a/Insight.Tinkoff.Invest/Dto/Portfolio/Responses/CurrenciesResponse.cs b/Insight.Tinkoff.Invest/Dto/Portfolio/Responses/CurrenciesResponse.cs index e908684..4077c0b 100644 --- a/Insight.Tinkoff.Invest/Dto/Portfolio/Responses/CurrenciesResponse.cs +++ b/Insight.Tinkoff.Invest/Dto/Portfolio/Responses/CurrenciesResponse.cs @@ -7,10 +7,11 @@ namespace Insight.Tinkoff.Invest.Dto.Responses { public sealed class CurrenciesResponse : ResponseBase { + [JsonProperty] public IReadOnlyCollection Currencies { get; } [JsonConstructor] - public CurrenciesResponse([JsonProperty("payload")] CurrenciesResponsePayload payload) + public CurrenciesResponse(CurrenciesResponsePayload payload) { Currencies = payload.Currencies; } diff --git a/Insight.Tinkoff.Invest/Dto/Portfolio/Responses/PortfolioResponse.cs b/Insight.Tinkoff.Invest/Dto/Portfolio/Responses/PortfolioResponse.cs index 02ac8fb..94e91cc 100644 --- a/Insight.Tinkoff.Invest/Dto/Portfolio/Responses/PortfolioResponse.cs +++ b/Insight.Tinkoff.Invest/Dto/Portfolio/Responses/PortfolioResponse.cs @@ -7,10 +7,11 @@ namespace Insight.Tinkoff.Invest.Dto.Responses { public sealed class PortfolioResponse : ResponseBase { + [JsonProperty] public IReadOnlyCollection Positions { get; } [JsonConstructor] - public PortfolioResponse([JsonProperty("payload")] PortfolioResponsePayload payload) + public PortfolioResponse(PortfolioResponsePayload payload) { Positions = payload.Positions; } diff --git a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeCandleMessage.cs b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeCandleMessage.cs index 9efa9e8..c89698c 100644 --- a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeCandleMessage.cs +++ b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeCandleMessage.cs @@ -1,3 +1,4 @@ +using System; using Insight.Tinkoff.Invest.Dto.Payloads; namespace Insight.Tinkoff.Invest.Dto.Messages @@ -6,9 +7,18 @@ public sealed class SubscribeCandleMessage : IWsMessage { public string Event => EventType.SubscribeCandle; - public string Figi { get; set; } + public SubscribeCandleMessage(string figi, CandleInterval interval) + { + if (string.IsNullOrWhiteSpace(figi)) + throw new ArgumentNullException(nameof(figi)); + + Figi = figi; + Interval = interval; + } + + public string Figi { get; private set; } - public CandleInterval Interval { get; set; } + public CandleInterval Interval { get; private set; } public override int GetHashCode() { diff --git a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeInstrumentInfoMessage.cs b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeInstrumentInfoMessage.cs index 541d516..c4eb4de 100644 --- a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeInstrumentInfoMessage.cs +++ b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeInstrumentInfoMessage.cs @@ -8,7 +8,14 @@ public sealed class SubscribeInstrumentInfoMessage : IWsMessage public string Figi { get; set; } - + public SubscribeInstrumentInfoMessage(string figi) + { + if (string.IsNullOrWhiteSpace(figi)) + throw new ArgumentNullException(nameof(figi)); + + Figi = figi; + } + public override int GetHashCode() { return (Figi != null ? Figi.GetHashCode() : 0); diff --git a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeOrderBookMessage.cs b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeOrderBookMessage.cs index a81a6f9..2af06fe 100644 --- a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeOrderBookMessage.cs +++ b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/SubscribeOrderBookMessage.cs @@ -1,3 +1,5 @@ +using System; + namespace Insight.Tinkoff.Invest.Dto.Messages { public sealed class SubscribeOrderBookMessage : IWsMessage @@ -7,6 +9,15 @@ public sealed class SubscribeOrderBookMessage : IWsMessage public string Figi { get; set; } public int Depth { get; set; } + + public SubscribeOrderBookMessage(string figi, int depth) + { + if (string.IsNullOrWhiteSpace(figi)) + throw new ArgumentNullException(nameof(figi)); + + Figi = figi; + Depth = depth; + } public override int GetHashCode() { diff --git a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeCandleMessage.cs b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeCandleMessage.cs index 046faed..9c97ffa 100644 --- a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeCandleMessage.cs +++ b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeCandleMessage.cs @@ -1,3 +1,4 @@ +using System; using Insight.Tinkoff.Invest.Dto.Payloads; namespace Insight.Tinkoff.Invest.Dto.Messages @@ -6,8 +7,17 @@ public sealed class UnsubscribeCandleMessage : IWsMessage { public string Event => EventType.UnubscribeCandle; - public string Figi { get; set; } + public UnsubscribeCandleMessage(string figi, CandleInterval interval) + { + if (string.IsNullOrWhiteSpace(figi)) + throw new ArgumentNullException(nameof(figi)); + + Figi = figi; + Interval = Interval; + } + + public string Figi { get; private set; } - public CandleInterval Interval { get; set; } + public CandleInterval Interval { get; private set; } } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeInstrumentInfo.cs b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeInstrumentInfo.cs index 7bbda18..e72eedc 100644 --- a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeInstrumentInfo.cs +++ b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeInstrumentInfo.cs @@ -1,3 +1,5 @@ +using System; + namespace Insight.Tinkoff.Invest.Dto.Messages { public sealed class UnsubscribeInstrumentInfo : IWsMessage @@ -5,5 +7,13 @@ public sealed class UnsubscribeInstrumentInfo : IWsMessage public string Event => EventType.UnubscribeInstrumentInfo; public string Figi { get; set; } + + public UnsubscribeInstrumentInfo(string figi) + { + if (string.IsNullOrWhiteSpace(figi)) + throw new ArgumentNullException(nameof(figi)); + + Figi = figi; + } } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeOrderBookMessage.cs b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeOrderBookMessage.cs index 57de212..dccb965 100644 --- a/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeOrderBookMessage.cs +++ b/Insight.Tinkoff.Invest/Dto/Stream/Messages/Out/UnsubscribeOrderBookMessage.cs @@ -1,11 +1,22 @@ +using System; + namespace Insight.Tinkoff.Invest.Dto.Messages { public sealed class UnsubscribeOrderBookMessage : IWsMessage { public string Event => EventType.UnsbscribeOrderBook; - - public string Figi { get; set; } - - public int Depth { get; set; } + + public UnsubscribeOrderBookMessage(string figi, int depth) + { + if (string.IsNullOrWhiteSpace(figi)) + throw new ArgumentNullException(nameof(figi)); + + Figi = figi; + Depth = depth; + } + + public string Figi { get; private set; } + + public int Depth { get; private set; } } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Dto/Stream/Payloads/CandlePayload.cs b/Insight.Tinkoff.Invest/Dto/Stream/Payloads/CandlePayload.cs index b446678..7fec8d2 100644 --- a/Insight.Tinkoff.Invest/Dto/Stream/Payloads/CandlePayload.cs +++ b/Insight.Tinkoff.Invest/Dto/Stream/Payloads/CandlePayload.cs @@ -5,43 +5,64 @@ namespace Insight.Tinkoff.Invest.Dto.Payloads { public sealed class CandlePayload { - public string Figi { get; set; } + [JsonConstructor] + public CandlePayload(string figi, + [JsonProperty("o")] double open, + [JsonProperty("c")] double close, + [JsonProperty("h")] double high, + [JsonProperty("l")] double low, + [JsonProperty("v")] double volume, + DateTimeOffset time, + CandleInterval interval) + { + Figi = figi; + Open = open; + Close = close; + High = high; + Low = low; + Volume = volume; + Time = time; + Interval = interval; + } + + [JsonProperty] + public string Figi { get; private set; } /// /// Цена открытия /// - [JsonProperty("o")] - public double Open { get; set; } + [JsonProperty] + public double Open { get;private set; } /// /// Цена закрытия /// - [JsonProperty("c")] - public double Close { get; set; } + [JsonProperty] + public double Close { get;private set; } /// /// Наибольшая цена /// - [JsonProperty("h")] - public double High { get; set; } + [JsonProperty] + public double High { get; private set; } /// /// Наименьшая цена /// - [JsonProperty("l")] - public double Low { get; set; } + [JsonProperty] + public double Low { get;private set; } /// /// Объем торгов /// - [JsonProperty("v")] - public double Volume { get; set; } + [JsonProperty] + public double Volume { get; private set; } /// /// Время /// - public DateTimeOffset Time { get; set; } + public DateTimeOffset Time { get; private set; } - public CandleInterval Interval { get; set; } + public CandleInterval Interval { get; private set; } } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Dto/Stream/Payloads/ErrorMessagePayload.cs b/Insight.Tinkoff.Invest/Dto/Stream/Payloads/ErrorMessagePayload.cs index 3e5330b..2a02632 100644 --- a/Insight.Tinkoff.Invest/Dto/Stream/Payloads/ErrorMessagePayload.cs +++ b/Insight.Tinkoff.Invest/Dto/Stream/Payloads/ErrorMessagePayload.cs @@ -4,9 +4,18 @@ namespace Insight.Tinkoff.Invest.Dto.Payloads { public sealed class ErrorMessagePayload { - [JsonProperty("request_id")] - public string RequestId { get; set; } - - public string Error { get; set; } + [JsonConstructor] + public ErrorMessagePayload( + [JsonProperty("request_id")] string requestId, + string error) + { + RequestId = requestId; + Error = error; + } + + [JsonProperty] + public string RequestId { get; private set; } + + public string Error { get; private set; } } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Dto/Stream/Payloads/InstrumentInfoPayload.cs b/Insight.Tinkoff.Invest/Dto/Stream/Payloads/InstrumentInfoPayload.cs index 4ee86f1..3feb24f 100644 --- a/Insight.Tinkoff.Invest/Dto/Stream/Payloads/InstrumentInfoPayload.cs +++ b/Insight.Tinkoff.Invest/Dto/Stream/Payloads/InstrumentInfoPayload.cs @@ -4,41 +4,63 @@ namespace Insight.Tinkoff.Invest.Dto.Payloads { public sealed class InstrumentInfoPayload { - public string Figi { get; set; } - + [JsonConstructor] + public InstrumentInfoPayload( + string figi, + [JsonProperty("trade_status")] TradeStatus tradeStatus, + [JsonProperty("min_price_increment")] decimal minPriceIncrement, + decimal lot, + [JsonProperty("accrued_interest")] decimal? accruedInterest, + [JsonProperty("limit_up")] decimal? limitUp, + [JsonProperty("limit_down")] decimal? limitDown) + { + Figi = figi; + TradeStatus = tradeStatus; + MinPriceIncrement = minPriceIncrement; + Lot = lot; + AccruedInterest = accruedInterest; + LimitUp = limitUp; + LimitDown = limitDown; + } + + /// + /// Figi + /// + public string Figi { get; private set; } + /// /// Статус торгов /// - [JsonProperty("trade_status")] - public TradeStatus TradeStatus { get; set; } - + [JsonProperty] + public TradeStatus TradeStatus { get; private set; } + /// /// Шаг цены /// - [JsonProperty("min_price_increment")] - public decimal MinPriceIncrement { get; set; } - + [JsonProperty] + public decimal MinPriceIncrement { get; private set; } + /// /// Лот /// - public decimal Lot { get; set; } - + public decimal Lot { get; private set; } + /// /// НКД. Возвращается только для бондов /// - [JsonProperty("accrued_interest")] - public decimal? AccruedInterest { get; set; } - + [JsonProperty] + public decimal? AccruedInterest { get; private set; } + /// /// Верхняя граница заявки. Возвращается только для RTS инструментов /// - [JsonProperty("limit_up")] - public decimal? LimitUp { get; set; } - + [JsonProperty] + public decimal? LimitUp { get; private set; } + /// /// Нижняя граница заявки. Возвращается только для RTS инструментов /// - [JsonProperty("limit_down")] - public decimal? LimitDown { get; set; } + [JsonProperty] + public decimal? LimitDown { get; private set; } } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Dto/Stream/Payloads/OrderBookPayload.cs b/Insight.Tinkoff.Invest/Dto/Stream/Payloads/OrderBookPayload.cs index c54d831..3dba8d2 100644 --- a/Insight.Tinkoff.Invest/Dto/Stream/Payloads/OrderBookPayload.cs +++ b/Insight.Tinkoff.Invest/Dto/Stream/Payloads/OrderBookPayload.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; @@ -8,18 +9,18 @@ public class OrderBookPayload { [JsonConstructor] public OrderBookPayload( - [JsonProperty("figi")] string figi, - [JsonProperty("depth")] int depth, - [JsonProperty("asks")] IReadOnlyCollection> asks, - [JsonProperty("bids")] IReadOnlyCollection> bids) + string figi, + int depth, + IReadOnlyCollection> asks, + IReadOnlyCollection> bids) { Figi = figi; Depth = depth; Asks = asks - .Select(x => new LotOffer {Price = x[0], Quantity = x[1]}) + .Select(x => new LotOffer(x[0], x[1])) .ToList(); Bids = bids - .Select(x => new LotOffer {Price = x[0], Quantity = x[1]}) + .Select(x => new LotOffer(x[0], x[1])) .ToList(); } @@ -43,8 +44,17 @@ public OrderBookPayload( public sealed class LotOffer { - public decimal Price { get; set; } + public LotOffer(decimal price, decimal quantity) + { + if (quantity == 0) + throw new ArgumentException("Quantity can not be 0"); + + Price = price; + Quantity = quantity; + } + + public decimal Price { get; private set; } - public decimal Quantity { get; set; } + public decimal Quantity { get; private set; } } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Infrastructure/Configurations/AccessConfiguration.cs b/Insight.Tinkoff.Invest/Infrastructure/Configurations/RestConfiguration.cs similarity index 82% rename from Insight.Tinkoff.Invest/Infrastructure/Configurations/AccessConfiguration.cs rename to Insight.Tinkoff.Invest/Infrastructure/Configurations/RestConfiguration.cs index a8460a8..c85670b 100644 --- a/Insight.Tinkoff.Invest/Infrastructure/Configurations/AccessConfiguration.cs +++ b/Insight.Tinkoff.Invest/Infrastructure/Configurations/RestConfiguration.cs @@ -1,6 +1,6 @@ namespace Insight.Tinkoff.Invest.Infrastructure.Configurations { - public sealed class TinkoffRestServiceConfiguration + public sealed class RestConfiguration { public string AccessToken { get; set; } diff --git a/Insight.Tinkoff.Invest/Infrastructure/Configurations/StreamMarketServiceConfiguration.cs b/Insight.Tinkoff.Invest/Infrastructure/Configurations/StreamConfiguration.cs similarity index 65% rename from Insight.Tinkoff.Invest/Infrastructure/Configurations/StreamMarketServiceConfiguration.cs rename to Insight.Tinkoff.Invest/Infrastructure/Configurations/StreamConfiguration.cs index ff781e2..7d7e118 100644 --- a/Insight.Tinkoff.Invest/Infrastructure/Configurations/StreamMarketServiceConfiguration.cs +++ b/Insight.Tinkoff.Invest/Infrastructure/Configurations/StreamConfiguration.cs @@ -1,9 +1,9 @@ namespace Insight.Tinkoff.Invest.Infrastructure.Configurations { - public sealed class StreamMarketServiceConfiguration + public sealed class StreamConfiguration { public string Address { get; set; } = "wss://api-invest.tinkoff.ru/openapi/md/v1/md-openapi/ws"; - public string Token { get; set; } + public string AccessToken { get; set; } } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Infrastructure/Extensions/EnumExtensions.cs b/Insight.Tinkoff.Invest/Infrastructure/Extensions/EnumExtensions.cs index 551390d..34d600f 100644 --- a/Insight.Tinkoff.Invest/Infrastructure/Extensions/EnumExtensions.cs +++ b/Insight.Tinkoff.Invest/Infrastructure/Extensions/EnumExtensions.cs @@ -5,7 +5,7 @@ namespace Insight.Tinkoff.Invest.Infrastructure.Extensions { - public static class EnumExtensions + internal static class EnumExtensions { public static string GetEnumMemberAttributeValue(this T e) where T : IConvertible { diff --git a/Insight.Tinkoff.Invest/Infrastructure/Extensions/ObservableEx.cs b/Insight.Tinkoff.Invest/Infrastructure/Extensions/ObservableExtensions.cs similarity index 93% rename from Insight.Tinkoff.Invest/Infrastructure/Extensions/ObservableEx.cs rename to Insight.Tinkoff.Invest/Infrastructure/Extensions/ObservableExtensions.cs index 3b356cb..76e8e23 100644 --- a/Insight.Tinkoff.Invest/Infrastructure/Extensions/ObservableEx.cs +++ b/Insight.Tinkoff.Invest/Infrastructure/Extensions/ObservableExtensions.cs @@ -4,7 +4,7 @@ namespace Insight.Tinkoff.Invest.Infrastructure.Extensions { - public static class ObservableEx + public static class ObservableExtensions { private static IEnumerable> RepeatInfinite(IObservable source, TimeSpan dueTime) diff --git a/Insight.Tinkoff.Invest/Infrastructure/Json/JSerializer.cs b/Insight.Tinkoff.Invest/Infrastructure/Json/JSerializer.cs index ab610b9..49314c9 100644 --- a/Insight.Tinkoff.Invest/Infrastructure/Json/JSerializer.cs +++ b/Insight.Tinkoff.Invest/Infrastructure/Json/JSerializer.cs @@ -4,7 +4,7 @@ namespace Insight.Tinkoff.Invest.Infrastructure.Json { - public static class JSerializer + internal static class JSerializer { private static readonly JsonSerializerSettings _settings; diff --git a/Insight.Tinkoff.Invest/Infrastructure/Services/RestService.cs b/Insight.Tinkoff.Invest/Infrastructure/Services/RestService.cs index de801a9..5d2fc76 100644 --- a/Insight.Tinkoff.Invest/Infrastructure/Services/RestService.cs +++ b/Insight.Tinkoff.Invest/Infrastructure/Services/RestService.cs @@ -9,7 +9,7 @@ namespace Insight.Tinkoff.Invest.Infrastructure.Services { - public abstract class RestService + internal abstract class RestService { private HttpClient _client; @@ -23,7 +23,7 @@ protected RestService(string baseUrl) BaseUrl = baseUrl; } - protected async Task Post(string path, TI payload, CancellationToken cancellationToken = default) + internal virtual async Task Post(string path, TI payload, CancellationToken cancellationToken = default) { var request = new HttpRequestMessage(HttpMethod.Post, GetRequestUrl(path)); if (payload != null) @@ -34,7 +34,7 @@ protected async Task Post(string path, TI payload, CancellationToken return await GetResponseItem(path, response); } - protected async Task Get(string path, CancellationToken cancellationToken = default) + internal virtual async Task Get(string path, CancellationToken cancellationToken = default) { var request = new HttpRequestMessage(HttpMethod.Get, GetRequestUrl(path)); var response = await EnsureHttpClientCreated() @@ -42,7 +42,7 @@ protected async Task Get(string path, CancellationToken cancellationToken return await GetResponseItem(path, response); } - protected async Task Delete(string path, CancellationToken cancellationToken = default) + internal virtual async Task Delete(string path, CancellationToken cancellationToken = default) { var request = new HttpRequestMessage(HttpMethod.Delete, GetRequestUrl(path)); var response = await EnsureHttpClientCreated() @@ -50,7 +50,7 @@ protected async Task Delete(string path, CancellationToken cancellationTok return await GetResponseItem(path, response); } - protected async Task Put(string path, TI payload, CancellationToken cancellationToken = default) + internal virtual async Task Put(string path, TI payload, CancellationToken cancellationToken = default) { var request = new HttpRequestMessage(HttpMethod.Post, GetRequestUrl(path)); if (payload != null) @@ -71,7 +71,7 @@ protected virtual async Task GetResponseItem(string path, HttpResponseMess return JSerializer.Deserialize(json); } - protected Uri GetRequestUrl(string path) + private Uri GetRequestUrl(string path) { return new UriBuilder($"{BaseUrl}{path}").Uri; } diff --git a/Insight.Tinkoff.Invest/Infrastructure/Services/TinkoffRestService.cs b/Insight.Tinkoff.Invest/Infrastructure/Services/TinkoffRestService.cs index a1d0d30..08dcb3e 100644 --- a/Insight.Tinkoff.Invest/Infrastructure/Services/TinkoffRestService.cs +++ b/Insight.Tinkoff.Invest/Infrastructure/Services/TinkoffRestService.cs @@ -2,6 +2,7 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Threading; using System.Threading.Tasks; using Insight.Tinkoff.Invest.Infrastructure.Configurations; using Insight.Tinkoff.Invest.Infrastructure.Exceptions; @@ -9,23 +10,29 @@ namespace Insight.Tinkoff.Invest.Infrastructure.Services { - public abstract class TinkoffRestService : RestService + internal sealed class TinkoffRestService : RestService { - protected TinkoffRestServiceConfiguration Configuration { get; } + internal RestConfiguration Configuration { get; } - protected string SandboxBasePath { get; } = "/openapi/sandbox"; - - protected string BasePath { get; } = "/openapi"; + internal string SandboxBasePath { get; } = "/openapi/sandbox"; - protected TinkoffRestService(TinkoffRestServiceConfiguration configuration) : base( - configuration.BaseUrl) + internal string BasePath { get; } = "/openapi"; + + internal TinkoffRestService(RestConfiguration configuration) : + base(configuration.BaseUrl) { - if(configuration == null) + if (configuration == null) throw new ArgumentNullException(nameof(configuration)); Configuration = configuration; } + internal override Task Get(string path, CancellationToken cancellationToken = default) + => base.Get(GetPath(path), cancellationToken); + + internal override Task Post(string path, TI payload, CancellationToken cancellationToken = default) + => base.Post(GetPath(path), payload, cancellationToken); + protected override async Task GetResponseItem(string path, HttpResponseMessage response) { var json = await GetResponseString(response); @@ -34,17 +41,23 @@ protected override async Task GetResponseItem(string path, HttpResponseMes var errorResponse = JSerializer.Deserialize(json); if (errorResponse == null) throw new RestServiceException(GetRestServiceExceptionMessage(path, response.StatusCode)); - + throw new RestServiceException(errorResponse.Payload.Message, errorResponse); } return JSerializer.Deserialize(json); } + private string GetPath(string path) + { + return $"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/{path}"; + } + protected override HttpClient CreateClient() - { - var client = new HttpClient { BaseAddress = new Uri(BaseUrl) }; - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Configuration.AccessToken); + { + var client = new HttpClient {BaseAddress = new Uri(BaseUrl)}; + client.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("Bearer", Configuration.AccessToken); return client; } } diff --git a/Insight.Tinkoff.Invest/Insight.Tinkoff.Invest.csproj b/Insight.Tinkoff.Invest/Insight.Tinkoff.Invest.csproj index 0f74c9c..bb3a05e 100644 --- a/Insight.Tinkoff.Invest/Insight.Tinkoff.Invest.csproj +++ b/Insight.Tinkoff.Invest/Insight.Tinkoff.Invest.csproj @@ -8,7 +8,7 @@ https://github.com/InsightAppDev/TinkoffInvestNetSdk/ https://github.com/InsightAppDev/TinkoffInvestNetSdk/ Github - 1.1.0 + 1.3.0 Insight.Tinkoff.InvestSdk netstandard2.0;netcoreapp3.0 disable diff --git a/Insight.Tinkoff.Invest/Services/Rest/MarketService.cs b/Insight.Tinkoff.Invest/Services/Rest/MarketService.cs index 9c6b83a..61f4d29 100644 --- a/Insight.Tinkoff.Invest/Services/Rest/MarketService.cs +++ b/Insight.Tinkoff.Invest/Services/Rest/MarketService.cs @@ -11,55 +11,65 @@ namespace Insight.Tinkoff.Invest.Services { - public sealed class MarketService : TinkoffRestService, IMarketService + public sealed class MarketService : IMarketService { - public MarketService(TinkoffRestServiceConfiguration configuration) : base( - configuration) + private readonly TinkoffRestService _rest; + + public MarketService(RestConfiguration configuration) { + if (configuration == null) + throw new ArgumentNullException(nameof(configuration)); + + _rest = new TinkoffRestService(configuration); } public Task GetBonds(CancellationToken cancellationToken = default) { - return Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/market/bonds", cancellationToken); + return _rest.Get("market/bonds", cancellationToken); } public Task GetCurrencies(CancellationToken cancellationToken = default) { - return Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/market/currencies", cancellationToken); + return _rest.Get("market/currencies", cancellationToken); } public Task GetEtfs(CancellationToken cancellationToken = default) { - return Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/market/etfs", cancellationToken); + return _rest.Get("market/etfs", cancellationToken); } public Task GetStocks(CancellationToken cancellationToken = default) { - return Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/market/stocks", cancellationToken); + return _rest.Get("market/stocks", cancellationToken); } - public Task SearchByFigi(string figi, CancellationToken cancellationToken = default) + public Task SearchByFigi(string figi, + CancellationToken cancellationToken = default) { - return Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/market/search/by-figi?figi={figi}", cancellationToken); + return _rest.Get($"market/search/by-figi?figi={figi}", cancellationToken); } - public Task SearchByTicker(string ticker, CancellationToken cancellationToken = default) + public Task SearchByTicker(string ticker, + CancellationToken cancellationToken = default) { - return Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/market/search/by-ticker?ticker={ticker}", cancellationToken); + return _rest.Get($"market/search/by-ticker?ticker={ticker}", + cancellationToken); } - public Task GetOrderBook(string figi, int depth, CancellationToken cancellationToken = default) + public Task GetOrderBook(string figi, int depth, + CancellationToken cancellationToken = default) { - return Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/market/orderbook?figi={figi}&depth={depth}", cancellationToken); + return _rest.Get($"market/orderbook?figi={figi}&depth={depth}", cancellationToken); + } - } - public Task GetCandles(string figi, DateTime from, DateTime to, CandleInterval interval, CancellationToken cancellationToken = default) { var fromEncoded = HttpUtility.UrlEncode(from.ToString("yyyy-MM-ddTHH:mm:ss.ffffffK")); var toEncoded = HttpUtility.UrlEncode(to.ToString("yyyy-MM-ddTHH:mm:ss.ffffffK")); - return Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/market/candles?figi={figi}&from={fromEncoded}&to={toEncoded}&interval={interval.GetEnumMemberAttributeValue()}", cancellationToken); + return _rest.Get( + $"market/candles?figi={figi}&from={fromEncoded}&to={toEncoded}&interval={interval.GetEnumMemberAttributeValue()}", + cancellationToken); } } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Services/Rest/OperationService.cs b/Insight.Tinkoff.Invest/Services/Rest/OperationService.cs index 735fb3a..00c220f 100644 --- a/Insight.Tinkoff.Invest/Services/Rest/OperationService.cs +++ b/Insight.Tinkoff.Invest/Services/Rest/OperationService.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using System.Web; using Insight.Tinkoff.Invest.Domain; @@ -10,12 +11,17 @@ namespace Insight.Tinkoff.Invest.Services { - public sealed class OperationService : TinkoffRestService, IOperationService + public sealed class OperationService : IOperationService { + private readonly TinkoffRestService _rest; + public OperationService( - TinkoffRestServiceConfiguration configuration) : - base(configuration) + RestConfiguration configuration) { + if (configuration == null) + throw new ArgumentNullException(nameof(configuration)); + + _rest = new TinkoffRestService(configuration); } public async Task Get(OperationsFilter filter, @@ -23,8 +29,8 @@ public async Task Get(OperationsFilter filter, { var from = HttpUtility.UrlEncode(filter.From.ToString("yyyy-MM-ddTHH:mm:ss.ffffffK")); var to = HttpUtility.UrlEncode(filter.To.ToString("yyyy-MM-ddTHH:mm:ss.ffffffK")); - return await Get( - $"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/operations?from={from}&to={to}&interval={filter.Interval.GetEnumMemberAttributeValue()}&figi={filter.Figi}", + return await _rest.Get( + $"operations?from={from}&to={to}&interval={filter.Interval.GetEnumMemberAttributeValue()}&figi={filter.Figi}", cancellationToken); } } diff --git a/Insight.Tinkoff.Invest/Services/Rest/OrderService.cs b/Insight.Tinkoff.Invest/Services/Rest/OrderService.cs index 0ccc434..1c2db57 100644 --- a/Insight.Tinkoff.Invest/Services/Rest/OrderService.cs +++ b/Insight.Tinkoff.Invest/Services/Rest/OrderService.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using Insight.Tinkoff.Invest.Domain; using Insight.Tinkoff.Invest.Dto; @@ -9,28 +10,33 @@ namespace Insight.Tinkoff.Invest.Services { - public sealed class OrderService : TinkoffRestService, IOrderService + public sealed class OrderService : IOrderService { - public OrderService(TinkoffRestServiceConfiguration configuration) : base( - configuration) + private readonly TinkoffRestService _rest; + + public OrderService(RestConfiguration configuration) { + if (configuration == null) + throw new ArgumentNullException(nameof(configuration)); + + _rest = new TinkoffRestService(configuration); } public Task Cancel(string orderId, CancellationToken cancellationToken = default) { - return Post($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/orders/cancel?orderId={orderId}", null, + return _rest.Post($"orders/cancel?orderId={orderId}", null, cancellationToken); } public Task Get(CancellationToken cancellationToken = default) { - return Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/orders", cancellationToken); + return _rest.Get("orders", cancellationToken); } - public Task PostLimitOrder(string figi, LimitOrderRequest request, + public Task PlaceLimitOrder(string figi, PlaceLimitOrderRequest request, CancellationToken cancellationToken = default) { - return Post($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/orders/limit-order?figi={figi}", request, + return _rest.Post($"orders/limit-order?figi={figi}", request, cancellationToken); } } diff --git a/Insight.Tinkoff.Invest/Services/Rest/PortfolioService.cs b/Insight.Tinkoff.Invest/Services/Rest/PortfolioService.cs index 6190892..bf86617 100644 --- a/Insight.Tinkoff.Invest/Services/Rest/PortfolioService.cs +++ b/Insight.Tinkoff.Invest/Services/Rest/PortfolioService.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using Insight.Tinkoff.Invest.Domain; using Insight.Tinkoff.Invest.Dto.Responses; @@ -7,21 +8,26 @@ namespace Insight.Tinkoff.Invest.Services { - public sealed class PortfolioService : TinkoffRestService, IPortfolioService + public sealed class PortfolioService : IPortfolioService { - public PortfolioService(TinkoffRestServiceConfiguration configuration) : base( - configuration) + private readonly TinkoffRestService _rest; + + public PortfolioService(RestConfiguration configuration) { + if (configuration == null) + throw new ArgumentNullException(nameof(configuration)); + + _rest = new TinkoffRestService(configuration); } public async Task GetCurrencies(CancellationToken token = default) { - return await Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/portfolio/currencies", token); + return await _rest.Get($"portfolio/currencies", token); } public async Task GetPortfolio(CancellationToken token = default) { - return await Get($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/portfolio", token); + return await _rest.Get($"portfolio", token); } } } \ No newline at end of file diff --git a/Insight.Tinkoff.Invest/Services/Rest/SandboxService.cs b/Insight.Tinkoff.Invest/Services/Rest/SandboxService.cs index 0ba9456..fac390e 100644 --- a/Insight.Tinkoff.Invest/Services/Rest/SandboxService.cs +++ b/Insight.Tinkoff.Invest/Services/Rest/SandboxService.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using Insight.Tinkoff.Invest.Domain; using Insight.Tinkoff.Invest.Dto; @@ -8,39 +9,44 @@ namespace Insight.Tinkoff.Invest.Services { - public sealed class SandboxService : TinkoffRestService, ISandboxService + public sealed class SandboxService : ISandboxService { + private readonly TinkoffRestService _rest; + public SandboxService( - TinkoffRestServiceConfiguration configuration) : - base(configuration) + RestConfiguration configuration) { + if (configuration == null) + throw new ArgumentNullException(nameof(configuration)); + + _rest = new TinkoffRestService(configuration); } public async Task Register(CancellationToken cancellationToken = default) { - return await Post($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/sandbox/register", + return await _rest.Post($"sandbox/register", null, cancellationToken); } public async Task Clear(CancellationToken cancellationToken = default) { - return await Post($"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/sandbox/clear", null, + return await _rest.Post("sandbox/clear", null, cancellationToken); } public async Task SetCurrencyBalance(SandboxSetCurrencyBalanceRequest request, CancellationToken cancellationToken = default) { - return await Post( - $"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/sandbox/currencies/balance", request, + return await _rest.Post( + "sandbox/currencies/balance", request, cancellationToken); } public async Task SetPositionBalance(SandboxSetPositionBalanceRequest request, CancellationToken cancellationToken = default) { - return await Post( - $"{(Configuration.SandboxMode ? SandboxBasePath : BasePath)}/sandbox/positions/balance", request, + return await _rest.Post( + "sandbox/positions/balance", request, cancellationToken); } } diff --git a/Insight.Tinkoff.Invest/Services/Stream/StreamMarketService.cs b/Insight.Tinkoff.Invest/Services/Stream/StreamMarketService.cs index 4342b5c..b968651 100644 --- a/Insight.Tinkoff.Invest/Services/Stream/StreamMarketService.cs +++ b/Insight.Tinkoff.Invest/Services/Stream/StreamMarketService.cs @@ -16,14 +16,14 @@ namespace Insight.Tinkoff.Invest.Services public class StreamMarketService : IStreamMarketService { private ClientWebSocket _socket; - private readonly StreamMarketServiceConfiguration _configuration; + private readonly StreamConfiguration _configuration; private event MessageReceived OnMessageReceived; private bool Disposed { get; set; } - public StreamMarketService(StreamMarketServiceConfiguration configuration) + public StreamMarketService(StreamConfiguration configuration) { if (configuration == null) throw new ArgumentNullException(nameof(configuration)); @@ -73,7 +73,7 @@ private async Task EnsureSocketConnection() if (Interlocked.CompareExchange(ref _socket, new ClientWebSocket(), null) != null) return; - _socket.Options.SetRequestHeader("Authorization", $"Bearer {_configuration.Token}"); + _socket.Options.SetRequestHeader("Authorization", $"Bearer {_configuration.AccessToken}"); await _socket.ConnectAsync(new Uri(_configuration.Address), CancellationToken.None); await Receiving(); diff --git a/README.MD b/README.MD index b45253c..f9dd0c6 100644 --- a/README.MD +++ b/README.MD @@ -2,7 +2,7 @@ Unofficial Tinkoff Invest .Net Sdk ==================== [![Build Status](https://travis-ci.org/InsightAppDev/Insight.Tinkoff.InvestSdk.svg?branch=master)](https://travis-ci.org/InsightAppDev/Insight.Tinkoff.InvestSdk) [![nuget version](https://img.shields.io/nuget/v/Insight.Tinkoff.InvestSdk)](https://www.nuget.org/packages/Insight.Tinkoff.InvestSdk/) -![Nuget](https://img.shields.io/nuget/dt/Insight.Tinkoff.InvestSDK?color=%2300000) +[![Nuget](https://img.shields.io/nuget/dt/Insight.Tinkoff.InvestSDK?color=%2300000)](https://www.nuget.org/packages/Insight.Tinkoff.InvestSdk/) About ------------------- @@ -22,18 +22,18 @@ Get started * *SandboxService* - Взаимодействие с песочницей (Rest, реализует **[ISandboxService](https://github.com/InsightAppDev/TinkoffInvestNetSdk/blob/master/Insight.Tinkoff.Invest/Domain/Services/ISandboxService.cs)**) * *StreamMarketService* - Взаимодействие с API по протоколу WebSocket (WebSocket, Реализует **[IStreamMarketService](https://github.com/InsightAppDev/TinkoffInvestNetSdk/blob/master/Insight.Tinkoff.Invest/Domain/Services/IStreamMarketService.cs)**) -Все Rest сервисы инициализируются объектом конфигурации типа **TinkoffRestServiceConfiguration**: +Все Rest сервисы инициализируются объектом конфигурации типа **RestConfiguration**: * *string AccessToken* - Токен доступа к API * *string BaseUrl* - Базовый адрес API, default = "https://api-invest.tinkoff.ru" * *bool SandboxMode* - Признак активна ли песочница, default = true -StreamMarketService инициализируется объектом конфигурации типа **StreamMarketServiceConfiguration**: -* *string Token* - Токен доступа к API +StreamMarketService инициализируется объектом конфигурации типа **StreamConfiguration**: +* *string AccessToken* - Токен доступа к API * *string Address* - Адрес, по которому доступен WebSocket, default = "wss://api-invest.tinkoff.ru/openapi/md/v1/md-openapi/ws" StreamMarketService -------------------- -Механизм взаимодействия с WebSocket взят из [официального sdk](https://github.com/TinkoffCreditSystems/invest-openapi-csharp-sdk). StreamMarketService реализует интерфейс IStreamMarketService: +Механизм взаимодействия взят из [официального sdk](https://github.com/TinkoffCreditSystems/invest-openapi-csharp-sdk). StreamMarketService реализует интерфейс IStreamMarketService: ``` public interface IStreamMarketService { @@ -47,9 +47,9 @@ public interface IStreamMarketService Метод AsObservable() реализован с помощью [System.Reactive](https://www.nuget.org/packages/System.Reactive/), а именно с помощью *Observable.FromEventPattern*, благодаря этому вы получаете Push коллекцию, в которую будут приходить сообщения типа *WsMessage*: *CandleMessage*, *OrderBookMessage*, *InstrumentInfoMessage*. На выходе сообщения десериализуются в правильный тип на основе свойства Event, вы можете использовать Pattern Matching. Пример кода: ``` public sealed class Program { - private StreamMarketServiceConfiguration _config; + private StreamConfiguration _config; - public Program(StreamMarketServiceConfiguration config) { + public Program(StreamConfiguration config) { if(config == null) throw new ArgumentNullException(nameof(config));