diff --git a/Client/Client.csproj b/Client/Client.csproj
index 885878c23..c065fd5ae 100644
--- a/Client/Client.csproj
+++ b/Client/Client.csproj
@@ -7,12 +7,13 @@
-
-
-
+
+
+
+
diff --git a/Client/Components/BaseComponent.razor.cs b/Client/Components/BaseComponent.razor.cs
index 9e2437d26..80361fcd9 100644
--- a/Client/Components/BaseComponent.razor.cs
+++ b/Client/Components/BaseComponent.razor.cs
@@ -1,6 +1,7 @@
+using Distribution.Services;
using Microsoft.AspNetCore.Components;
-using Schedule.Runners;
using System;
+using System.Threading;
using System.Threading.Tasks;
namespace Client.Components
@@ -10,23 +11,16 @@ public class BaseComponent : ComponentBase
///
/// Updater
///
- protected virtual TimeRunner Updater { get; set; } = new()
- {
- Count = 1,
- Span = TimeSpan.FromMilliseconds(100)
- };
+ protected virtual ScheduleService Updater { get; set; } = new ScheduleService();
///
/// Render
///
- protected virtual Task Render(Action action)
+ protected virtual Task Render(Action action) => Updater.Send(() =>
{
- return Updater.Send(() =>
- {
- action();
- InvokeAsync(StateHasChanged);
-
- }).Task;
- }
+ action();
+ InvokeAsync(StateHasChanged);
+ Thread.Sleep(1);
+ }).Task;
}
}
diff --git a/Client/Components/ChartsComponent.razor.cs b/Client/Components/ChartsComponent.razor.cs
index a7aea6d0f..6c5220279 100644
--- a/Client/Components/ChartsComponent.razor.cs
+++ b/Client/Components/ChartsComponent.razor.cs
@@ -11,7 +11,7 @@
namespace Client.Components
{
- public partial class ChartsComponent : IDisposable, IAsyncDisposable
+ public partial class ChartsComponent : IDisposable
{
///
/// Reference to view control
@@ -89,7 +89,7 @@ public virtual Task UpdateItems(IList> inputs,
var domain = new DomainModel
{
- IndexDomain = new[] { Shapes.Count - (count ?? Shapes.Count), Shapes.Count }
+ IndexDomain = new int[] { Shapes.Count - (count ?? Shapes.Count), Shapes.Count }
};
return Render(() => View.Update(domain, Shapes));
@@ -108,20 +108,6 @@ public virtual void Clear()
///
/// Dispose
///
- ///
- public virtual ValueTask DisposeAsync()
- {
- Dispose();
-
- return new ValueTask(Task.CompletedTask);
- }
-
- ///
- /// Dispose
- ///
- public virtual void Dispose()
- {
- View?.DisposeAsync();
- }
+ public virtual void Dispose() => View?.Dispose();
}
}
diff --git a/Client/Components/PageComponent.razor.cs b/Client/Components/PageComponent.razor.cs
index 33adb1a97..1f9ae9250 100644
--- a/Client/Components/PageComponent.razor.cs
+++ b/Client/Components/PageComponent.razor.cs
@@ -1,10 +1,9 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Configuration;
-using Schedule.Runners;
using System;
+using System.Linq;
using System.Threading.Tasks;
using Terminal.Core.Domains;
-using Terminal.Core.Services;
namespace Client.Components
{
@@ -23,43 +22,69 @@ public partial class PageComponent
public virtual OrdersComponent OrdersView { get; set; }
public virtual PositionsComponent PositionsView { get; set; }
public virtual StatementsComponent StatementsView { get; set; }
- public virtual IConnector Adapter { get; set; }
+ public virtual IGateway Adapter { get; set; }
public virtual Action Setup { get; set; }
public virtual async Task OnConnect()
{
- OnDisconnect();
- Setup();
+ try
+ {
+ OnDisconnect();
+ Setup();
- IsConnection = true;
- IsSubscription = true;
+ IsConnection = true;
+ IsSubscription = true;
- await Adapter.Connect();
+ await Adapter.Connect();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
}
public virtual void OnDisconnect()
{
- IsConnection = false;
- IsSubscription = false;
+ try
+ {
+ Adapter?.Disconnect();
- Adapter?.Disconnect();
+ ChartsView.Clear();
+ ReportsView.Clear();
- ChartsView.Clear();
- ReportsView.Clear();
+ IsConnection = false;
+ IsSubscription = false;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
}
- public virtual async Task OnSubscribe()
+ public virtual void OnSubscribe()
{
- IsSubscription = true;
-
- await Adapter.Subscribe();
+ try
+ {
+ IsSubscription = true;
+ Adapter.Account.Instruments.ForEach(o => Adapter.Subscribe(o.Key));
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
}
public virtual void OnUnsubscribe()
{
- IsSubscription = false;
-
- Adapter.Unsubscribe();
+ try
+ {
+ IsSubscription = false;
+ Adapter.Account.Instruments.ForEach(o => Adapter.Unsubscribe(o.Key));
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
}
public virtual void OnOpenStatements()
diff --git a/Client/Pages/Pairs.razor.cs b/Client/Pages/Pairs.razor.cs
index c3fbdf42c..02552a8db 100644
--- a/Client/Pages/Pairs.razor.cs
+++ b/Client/Pages/Pairs.razor.cs
@@ -1,25 +1,22 @@
using Canvas.Core.Models;
using Canvas.Core.Shapes;
+using Client.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Configuration;
-using Schedule.Runners;
+using Simulation;
using SkiaSharp;
+using System;
using System.Collections.Generic;
using System.Linq;
-using System.Reactive.Linq;
using System.Threading.Tasks;
-using Client.Components;
-using Terminal.Connector.Simulation;
using Terminal.Core.Domains;
using Terminal.Core.Enums;
using Terminal.Core.Indicators;
using Terminal.Core.Models;
-using Terminal.Core.Services;
-using System;
namespace Client.Pages
{
- public partial class Pairs
+ public partial class Pairs : IDisposable
{
[Inject] IConfiguration Configuration { get; set; }
@@ -28,7 +25,6 @@ public partial class Pairs
///
const string _assetX = "GOOGL";
const string _assetY = "GOOG";
- const string _account = "Simulation";
protected virtual IAccount Account { get; set; }
protected virtual PageComponent View { get; set; }
@@ -38,49 +34,35 @@ protected override async Task OnAfterRenderAsync(bool setup)
{
if (setup)
{
- var comUp = new ComponentModel { Color = SKColors.DeepSkyBlue };
- var comDown = new ComponentModel { Color = SKColors.OrangeRed };
+ var indUp = new ComponentModel { Color = SKColors.DeepSkyBlue };
+ var indDown = new ComponentModel { Color = SKColors.OrangeRed };
+ var indAreas = new GroupShape();
+ var indCharts = new GroupShape();
- await View.ChartsView.Create(new GroupShape
- {
- Groups = new Dictionary
- {
- ["Prices"] = new GroupShape
- {
- Groups = new Dictionary
- {
- [nameof(OrderSideEnum.Buy)] = new ArrowShape { Component = comUp },
- [nameof(OrderSideEnum.Sell)] = new ArrowShape { Component = comDown },
- ["Range"] = new AreaShape { Component = comUp }
- }
- }
- }
- });
+ indCharts.Groups["Buy"] = new ArrowShape { Component = indUp };
+ indCharts.Groups["Sell"] = new ArrowShape { Component = indDown };
+ indCharts.Groups["Range"] = new AreaShape { Component = indUp };
+ indAreas.Groups["Prices"] = indCharts;
- var componentGain = new ComponentModel { Color = SKColors.OrangeRed, Size = 5 };
- var componentBalance = new ComponentModel { Color = SKColors.Black };
+ await View.ChartsView.Create(indAreas);
- await View.ReportsView.Create(new GroupShape
- {
- Groups = new Dictionary
- {
- ["Performance"] = new GroupShape
- {
- Groups = new Dictionary
- {
- ["PnL"] = new LineShape { Component = componentGain },
- ["Balance"] = new AreaShape { Component = componentBalance }
- }
- }
- }
- });
+ var pnlGain = new ComponentModel { Color = SKColors.OrangeRed, Size = 5 };
+ var pnlBalance = new ComponentModel { Color = SKColors.Black };
+ var pnlAreas = new GroupShape();
+ var pnlCharts = new GroupShape();
+
+ pnlCharts.Groups["PnL"] = new LineShape { Component = pnlGain };
+ pnlCharts.Groups["Balance"] = new AreaShape { Component = pnlBalance };
+ pnlAreas.Groups["Performance"] = pnlCharts;
+
+ await View.ReportsView.Create(pnlAreas);
View.Setup = () =>
{
Account = new Account
{
+ Name = "Demo",
Balance = 25000,
- Name = _account,
Instruments = new Dictionary
{
[_assetX] = new Instrument { Name = _assetX },
@@ -100,13 +82,10 @@ await View.ReportsView.Create(new GroupShape
Account
.Instruments
.Values
- .ForEach(o => o.Points.CollectionChanged += (o, e) =>
- {
- foreach (PointModel item in e.NewItems)
- {
- InstanceService.Instance.Send(OnData(item));
- }
- });
+ .ForEach(o => o.Points.CollectionChanged += (_, e) => e
+ .NewItems
+ .OfType()
+ .ForEach(async o => await OnData(o)));
};
}
@@ -175,38 +154,30 @@ private async Task OnData(PointModel point)
private (string, string) OpenPositions(IInstrument assetBuy, IInstrument assetSell)
{
- var messageSell = new StateModel
+ var orderSell = new OrderModel
{
- Action = ActionEnum.Create,
- Next = new OrderModel
+ Side = OrderSideEnum.Sell,
+ Type = OrderTypeEnum.Market,
+ Transaction = new()
{
- Side = OrderSideEnum.Sell,
- Type = OrderTypeEnum.Market,
- Transaction = new()
- {
- Volume = 1,
- Instrument = assetSell
- }
+ Volume = 1,
+ Instrument = assetSell
}
};
- var messageBuy = new StateModel
+ var orderBuy = new OrderModel
{
- Action = ActionEnum.Create,
- Next = new OrderModel
+ Side = OrderSideEnum.Buy,
+ Type = OrderTypeEnum.Market,
+ Transaction = new()
{
- Side = OrderSideEnum.Buy,
- Type = OrderTypeEnum.Market,
- Transaction = new()
- {
- Volume = 1,
- Instrument = assetBuy
- }
+ Volume = 1,
+ Instrument = assetBuy
}
};
- View.Adapter.OrderStream(messageSell);
- View.Adapter.OrderStream(messageBuy);
+ View.Adapter.CreateOrders(orderBuy);
+ View.Adapter.CreateOrders(orderSell);
var account = View.Adapter.Account;
var buy = account.ActivePositions.Values.First(o => o.Order.Side == OrderSideEnum.Buy);
@@ -215,7 +186,7 @@ private async Task OnData(PointModel point)
//points.Add(new PointModel { Time = buy.Time, Name = nameof(OrderSideEnum.Buy), Last = buy.OpenPrices.Last().Price });
//points.Add(new PointModel { Time = sell.Time, Name = nameof(OrderSideEnum.Sell), Last = sell.OpenPrices.Last().Price });
- return (messageSell.Next.Transaction.Id, messageBuy.Next.Transaction.Id);
+ return (orderSell.Transaction.Id, orderBuy.Transaction.Id);
}
private void ClosePositions()
@@ -223,12 +194,9 @@ private void ClosePositions()
foreach (var position in View.Adapter.Account.ActivePositions.Values)
{
var side = OrderSideEnum.Buy;
- var point = position.Order.Transaction.Instrument.Points.Last();
- var price = point.Ask;
if (Equals(position.Order.Side, OrderSideEnum.Buy))
{
- price = point.Bid;
side = OrderSideEnum.Sell;
}
@@ -243,14 +211,12 @@ private void ClosePositions()
}
};
- View.Adapter.OrderStream(new StateModel
- {
- Action = ActionEnum.Create,
- Next = order
- });
+ View.Adapter.CreateOrders(order);
//points.Add(new PointModel { Time = order.Time, Name = nameof(OrderSideEnum.Buy), Last = price });
}
}
+
+ public void Dispose() => View?.Adapter?.Disconnect();
}
}
diff --git a/Core/Core.csproj b/Core/Core.csproj
index 656ff1ade..87a4023ce 100644
--- a/Core/Core.csproj
+++ b/Core/Core.csproj
@@ -14,10 +14,9 @@
-
+
+
-
-
diff --git a/Core/Domains/Connector.cs b/Core/Domains/Connector.cs
deleted file mode 100644
index 212d36546..000000000
--- a/Core/Domains/Connector.cs
+++ /dev/null
@@ -1,293 +0,0 @@
-using FluentValidation.Results;
-using Mapper;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Terminal.Core.Enums;
-using Terminal.Core.Models;
-using Terminal.Core.Services;
-using Terminal.Core.Validators;
-
-namespace Terminal.Core.Domains
-{
- public interface IConnector : IDisposable
- {
- ///
- /// Production or Development mode
- ///
- EnvironmentEnum Mode { get; set; }
-
- ///
- /// Account
- ///
- IAccount Account { get; set; }
-
- ///
- /// Incoming data event
- ///
- Action> DataStream { get; set; }
-
- ///
- /// Send order event
- ///
- Action> OrderStream { get; set; }
-
- ///
- /// Restore state and initialize
- ///
- Task> Connect();
-
- ///
- /// Save state and dispose
- ///
- Task> Disconnect();
-
- ///
- /// Continue execution
- ///
- Task> Subscribe();
-
- ///
- /// Suspend execution
- ///
- Task> Unsubscribe();
-
- ///
- /// Get quote
- ///
- ///
- Task> GetPoint(PointMessageModel message);
-
- ///
- /// Get quotes history
- ///
- ///
- Task>> GetPoints(PointMessageModel message);
-
- ///
- /// Get option chains
- ///
- ///
- Task>> GetOptions(OptionMessageModel message);
-
- ///
- /// Send new orders
- ///
- ///
- Task> CreateOrders(params OrderModel[] orders);
-
- ///
- /// Update orders
- ///
- ///
- Task> UpdateOrders(params OrderModel[] orders);
-
- ///
- /// Cancel orders
- ///
- ///
- Task> DeleteOrders(params OrderModel[] orders);
- }
-
- ///
- /// Implementation
- ///
- public abstract class Connector : IConnector
- {
- ///
- /// Production or Sandbox
- ///
- public virtual EnvironmentEnum Mode { get; set; }
-
- ///
- /// Account
- ///
- public virtual IAccount Account { get; set; }
-
- ///
- /// Incoming data event
- ///
- public virtual Action> DataStream { get; set; }
-
- ///
- /// Send order event
- ///
- public virtual Action> OrderStream { get; set; }
-
- ///
- /// Constructor
- ///
- public Connector()
- {
- Mode = EnvironmentEnum.Paper;
-
- DataStream = o => { };
- OrderStream = o => { };
- }
-
- ///
- /// Restore state and initialize
- ///
- public abstract Task> Connect();
-
- ///
- /// Continue execution
- ///
- public abstract Task> Subscribe();
-
- ///
- /// Save state and dispose
- ///
- public abstract Task> Disconnect();
-
- ///
- /// Unsubscribe from data streams
- ///
- public abstract Task> Unsubscribe();
-
- ///
- /// Get quote
- ///
- ///
- public abstract Task> GetPoint(PointMessageModel message);
-
- ///
- /// Get quotes history
- ///
- ///
- public abstract Task>> GetPoints(PointMessageModel message);
-
- ///
- /// Get option chains
- ///
- ///
- public abstract Task>> GetOptions(OptionMessageModel message);
-
- ///
- /// Send new orders
- ///
- ///
- public abstract Task> CreateOrders(params OrderModel[] orders);
-
- ///
- /// Update orders
- ///
- ///
- public abstract Task> UpdateOrders(params OrderModel[] orders);
-
- ///
- /// Cancel orders
- ///
- ///
- public abstract Task> DeleteOrders(params OrderModel[] orders);
-
- ///
- /// Dispose
- ///
- public virtual void Dispose() => Disconnect();
-
- ///
- /// Set missing order properties
- ///
- ///
- protected virtual IList CorrectOrders(params OrderModel[] orders)
- {
- foreach (var nextOrder in orders)
- {
- nextOrder.Type ??= OrderTypeEnum.Market;
- nextOrder.TimeSpan ??= OrderTimeSpanEnum.GTC;
- nextOrder.Transaction ??= new TransactionModel();
- nextOrder.Transaction.Time ??= DateTime.Now;
- nextOrder.Transaction.Price ??= GetOpenPrice(nextOrder);
- nextOrder.Transaction.Status ??= OrderStatusEnum.None;
- nextOrder.Transaction.Operation ??= OperationEnum.In;
- }
-
- return orders;
- }
-
- ///
- /// Ensure all properties have correct values
- ///
- ///
- protected virtual ResponseModel ValidateOrders(params OrderModel[] orders)
- {
- var map = Mapper.Map;
- var orderRules = InstanceService.Instance;
- var response = new ResponseModel();
-
- foreach (var order in orders)
- {
- var errors = new List();
-
- errors.AddRange(orderRules.Validate(order).Errors.Select(o => map(o, new ErrorModel())));
- errors.AddRange(order.Orders.SelectMany(o => orderRules.Validate(o).Errors.Select(o => map(o, new ErrorModel()))));
-
- response.Count += errors.Count;
- response.Items.Add(new ResponseItemModel
- {
- Data = order,
- Errors = errors
- });
- }
-
- return response;
- }
-
- ///
- /// Define open price based on order
- ///
- ///
- protected virtual double? GetOpenPrice(OrderModel nextOrder)
- {
- var pointModel = nextOrder?.Transaction?.Instrument?.Points?.LastOrDefault();
-
- if (pointModel is not null)
- {
- switch (nextOrder?.Side)
- {
- case OrderSideEnum.Buy: return pointModel.Ask;
- case OrderSideEnum.Sell: return pointModel.Bid;
- }
- }
-
- return null;
- }
-
- ///
- /// Update points
- ///
- ///
- protected virtual IList CorrectAccounts(params IAccount[] accounts)
- {
- foreach (var account in accounts)
- {
- account.InitialBalance = account.Balance;
- }
-
- return accounts;
- }
-
- ///
- /// Update points
- ///
- ///
- protected virtual IList CorrectPoints(params PointModel[] points)
- {
- foreach (var point in points)
- {
- var instrument = Account.Instruments[point.Instrument.Name];
- var estimates = Account.ActivePositions.Select(o => o.Value.GainLossEstimate).ToList();
-
- point.Instrument = instrument;
- point.TimeFrame = instrument.TimeFrame;
-
- instrument.Points.Add(point);
- instrument.PointGroups.Add(point, instrument.TimeFrame, true);
- }
-
- return points;
- }
- }
-}
diff --git a/Core/Enums/EnvironmentEnum.cs b/Core/Enums/EnvironmentEnum.cs
index 22b467d86..a9e9e39b5 100644
--- a/Core/Enums/EnvironmentEnum.cs
+++ b/Core/Enums/EnvironmentEnum.cs
@@ -4,6 +4,6 @@ public enum EnvironmentEnum : byte
{
None = 0,
Live = 1,
- Paper = 2
+ Sandbox = 2
}
}
diff --git a/Core/Extensions/Dictionary.cs b/Core/Extensions/Dictionary.cs
index 3212760ac..da89b39e4 100644
--- a/Core/Extensions/Dictionary.cs
+++ b/Core/Extensions/Dictionary.cs
@@ -7,7 +7,7 @@ public static class DictionaryExtensions
{
public static V Get(this IDictionary input, K index)
{
- return input.TryGetValue(index, out var value) ? value : default;
+ return index is not null && input.TryGetValue(index, out var value) ? value : default;
}
}
}
diff --git a/Core/Indicators/MovingAverageIndicator.cs b/Core/Indicators/MovingAverageIndicator.cs
index 49d1c7836..864a4f5f5 100644
--- a/Core/Indicators/MovingAverageIndicator.cs
+++ b/Core/Indicators/MovingAverageIndicator.cs
@@ -1,3 +1,4 @@
+using Distribution.Services;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
diff --git a/Core/Indicators/RelativeStrengthIndicator.cs b/Core/Indicators/RelativeStrengthIndicator.cs
index e88265a27..d5e5cd4bd 100644
--- a/Core/Indicators/RelativeStrengthIndicator.cs
+++ b/Core/Indicators/RelativeStrengthIndicator.cs
@@ -1,3 +1,4 @@
+using Distribution.Services;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
diff --git a/Core/Indicators/ScaleIndicator.cs b/Core/Indicators/ScaleIndicator.cs
index 9395cd4c5..574d29849 100644
--- a/Core/Indicators/ScaleIndicator.cs
+++ b/Core/Indicators/ScaleIndicator.cs
@@ -1,3 +1,4 @@
+using Distribution.Services;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
diff --git a/Core/Services/InstanceService.cs b/Core/Services/InstanceService.cs
deleted file mode 100644
index 08725b915..000000000
--- a/Core/Services/InstanceService.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace Terminal.Core.Services
-{
- ///
- /// Service to track account changes, including equity and quotes
- ///
- public class InstanceService where T: new()
- {
- private static readonly T _instance = new();
-
- ///
- /// Single instance
- ///
- public static T Instance => _instance;
-
- ///
- /// Constructor
- ///
- static InstanceService()
- {
- }
-
- ///
- /// Constructor
- ///
- private InstanceService()
- {
- }
- }
-}
diff --git a/Core/Validators/Validators.cs b/Core/Validators/Validators.cs
index 664ae140e..9c47cff4c 100644
--- a/Core/Validators/Validators.cs
+++ b/Core/Validators/Validators.cs
@@ -1,3 +1,4 @@
+using Distribution.Services;
using FluentValidation;
using System.Collections.Generic;
using Terminal.Core.Services;
diff --git a/Data/Options/GOOG b/Data/Options/GOOG
deleted file mode 100644
index 5737ea0cd..000000000
Binary files a/Data/Options/GOOG and /dev/null differ
diff --git a/Gateways/Simulation/Libs/Adapter.cs b/Gateways/Simulation/Libs/Adapter.cs
index 1ea7c11e8..30ece8885 100644
--- a/Gateways/Simulation/Libs/Adapter.cs
+++ b/Gateways/Simulation/Libs/Adapter.cs
@@ -1,21 +1,20 @@
-using FluentValidation.Results;
+using Distribution.Services;
using Mapper;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
-using System.Reactive.Concurrency;
-using System.Reactive.Linq;
using System.Threading.Tasks;
+using System.Timers;
using Terminal.Core.Domains;
using Terminal.Core.Enums;
using Terminal.Core.Extensions;
using Terminal.Core.Models;
-namespace Terminal.Connector.Simulation
+namespace Simulation
{
- public class Adapter : Core.Domains.Connector, IDisposable
+ public class Adapter : Gateway, IDisposable
{
///
/// Disposable connections
@@ -25,7 +24,7 @@ public class Adapter : Core.Domains.Connector, IDisposable
///
/// Disposable subscriptions
///
- protected IList _subscriptions;
+ protected IDictionary _subscriptions;
///
/// Instrument streams
@@ -42,16 +41,18 @@ public class Adapter : Core.Domains.Connector, IDisposable
///
public virtual string Source { get; set; }
+ public virtual ScheduleService Scheduler { get; set; } = new();
+
///
/// Constructor
///
public Adapter()
{
- Speed = 100;
+ Speed = 1000;
_connections = new List();
- _subscriptions = new List();
_instruments = new Dictionary();
+ _subscriptions = new Dictionary();
}
///
@@ -61,7 +62,7 @@ public override async Task> Connect()
{
await Disconnect();
- CorrectAccounts(Account);
+ SetupAccounts(Account);
_instruments = Account
.Instruments
@@ -69,7 +70,8 @@ public override async Task> Connect()
_instruments.ForEach(o => _connections.Add(o.Value));
- await Subscribe();
+ Account.Positions.CollectionChanged += OnPositionUpdate;
+ Account.Instruments.ForEach(async o => await Subscribe(o.Key));
return null;
}
@@ -77,30 +79,32 @@ public override async Task> Connect()
///
/// Subscribe to data streams
///
- public override async Task> Subscribe()
+ public override async Task> Subscribe(string name)
{
- await Unsubscribe();
+ await Unsubscribe(name);
- OrderStream += OnOrderUpdate;
- Account.Positions.CollectionChanged += OnPositionUpdate;
- Account.Instruments.ForEach(o => o.Value.Points.CollectionChanged += OnPointUpdate);
+ Account.Instruments[name].Points.CollectionChanged += OnPointUpdate;
- var span = TimeSpan.FromMilliseconds(Speed);
+ var span = TimeSpan.FromMicroseconds(Speed);
var points = new Dictionary();
- var scheduler = new EventLoopScheduler();
- var interval = Observable
- .Interval(span, scheduler)
- .Subscribe(o =>
+ var scheduler = InstanceService.Instance;
+ var interval = new Timer(span);
+
+ interval.Enabled = true;
+ interval.AutoReset = true;
+ interval.Elapsed += (sender, e) => scheduler.Send(() =>
+ {
+ var point = GetRecord(_instruments, points);
+
+ if (point is not null)
{
- var point = GetRecord(_instruments, points);
+ SetupPoints(point);
+ }
- if (point is not null)
- {
- CorrectPoints(point);
- }
- });
+ interval.Enabled = true;
+ });
- _subscriptions.Add(interval);
+ _subscriptions[name] = interval;
return null;
}
@@ -110,7 +114,8 @@ public override async Task> Subscribe()
///
public override Task> Disconnect()
{
- Unsubscribe();
+ Account.Instruments.ForEach(async o => await Unsubscribe(o.Key));
+ Account.Positions.CollectionChanged -= OnPositionUpdate;
_connections?.ForEach(o => o.Dispose());
_connections?.Clear();
@@ -121,14 +126,15 @@ public override Task> Disconnect()
///
/// Unsubscribe from data streams
///
- public override Task> Unsubscribe()
+ public override Task> Unsubscribe(string name)
{
- OrderStream -= OnOrderUpdate;
- Account.Positions.CollectionChanged -= OnPositionUpdate;
- Account.Instruments.ForEach(o => o.Value.Points.CollectionChanged -= OnPointUpdate);
+ Account.Instruments[name].Points.CollectionChanged -= OnPointUpdate;
- _subscriptions?.ForEach(o => o.Dispose());
- _subscriptions?.Clear();
+ if (_subscriptions.ContainsKey(name))
+ {
+ _subscriptions[name].Dispose();
+ _subscriptions.Remove(name);
+ }
return Task.FromResult>(null);
}
@@ -149,7 +155,7 @@ public override Task> GetPoint(PointMessageModel m
/// Create order and depending on the account, send it to the processing queue
///
///
- public override Task> CreateOrders(params OrderModel[] orders)
+ public override Task> CreateOrders(params OrderModel[] orders)
{
var response = ValidateOrders(CorrectOrders(orders).ToArray());
@@ -176,7 +182,7 @@ public override Task> CreateOrders(params OrderModel[]
/// Update orders
///
///
- public override Task> UpdateOrders(params OrderModel[] orders)
+ public override Task> UpdateOrders(params OrderModel[] orders)
{
var nextOrders = orders.Select(nextOrder =>
{
@@ -205,9 +211,9 @@ public override Task> UpdateOrders(params OrderModel[]
/// Recursively cancel orders
///
///
- public override Task> DeleteOrders(params OrderModel[] orders)
+ public override Task> DeleteOrders(params OrderModel[] orders)
{
- var response = new ResponseModel();
+ var response = new ResponseMapModel();
foreach (var nextOrder in orders)
{
diff --git a/Gateways/Simulation/Libs/Simulation.csproj b/Gateways/Simulation/Libs/Simulation.csproj
index f35f5b016..b143c9e31 100644
--- a/Gateways/Simulation/Libs/Simulation.csproj
+++ b/Gateways/Simulation/Libs/Simulation.csproj
@@ -13,6 +13,10 @@
MIT
+
+
+
+
diff --git a/Gateways/Simulation/Tests/Connectors.cs b/Gateways/Simulation/Tests/Connectors.cs
index b8c58bf8c..9d43c453e 100644
--- a/Gateways/Simulation/Tests/Connectors.cs
+++ b/Gateways/Simulation/Tests/Connectors.cs
@@ -1,10 +1,6 @@
+using Simulation;
using System;
-using System.Collections.Generic;
-using System.Linq;
-using Terminal.Connector.Simulation;
using Terminal.Core.Domains;
-using Terminal.Core.Enums;
-using Terminal.Core.Models;
namespace Terminal.Tests
{
@@ -21,374 +17,5 @@ public Connectors()
Balance = 50000
};
}
-
- //[Theory]
- //[InlineData(OrderTypeEnum.Stop)]
- //[InlineData(OrderTypeEnum.Limit)]
- //[InlineData(OrderTypeEnum.StopLimit)]
- //public void ValidateOrdersWithoutOpenPrice(OrderTypeEnum orderType)
- //{
- // var order = new OrderModel
- // {
- // Type = orderType
- // };
-
- // var error = "NotEmptyValidator";
- // var errors = base.ValidateOrders(order).Select(o => $"{o.PropertyName} {o.ErrorCode}");
-
- // Assert.Contains($"{nameof(order.Transaction.Price)} {error}", errors);
- //}
-
- //[Theory]
- //[InlineData(OrderSideEnum.Buy, OrderTypeEnum.Stop, 5.0, 10.0, "GreaterThanOrEqualValidator")]
- //[InlineData(OrderSideEnum.Sell, OrderTypeEnum.Stop, 10.0, 5.0, "LessThanOrEqualValidator")]
- //[InlineData(OrderSideEnum.Buy, OrderTypeEnum.Limit, 10.0, 5.0, "LessThanOrEqualValidator")]
- //[InlineData(OrderSideEnum.Sell, OrderTypeEnum.Limit, 5.0, 10.0, "GreaterThanOrEqualValidator")]
- //public void ValidateOrdersWithIncorrectPrice(
- // OrderSideEnum orderSide,
- // OrderTypeEnum orderType,
- // double orderPrice,
- // double price,
- // string error)
- //{
- // var order = GenerateOrder(AssetX, orderSide, orderType, 1.0, price, price, null, orderPrice);
- // var errors = base.ValidateOrders(order).Select(o => $"{o.PropertyName} {o.ErrorCode}");
-
- // Assert.Contains($"{nameof(order.Transaction.Price)} {error}", errors);
- //}
-
- //[Theory]
- //[InlineData(OrderSideEnum.Buy, 15.0, null, 10.0, "NotEmptyValidator", "GreaterThanOrEqualValidator")]
- //[InlineData(OrderSideEnum.Sell, 15.0, null, 5.0, "NotEmptyValidator", "LessThanOrEqualValidator")]
- //[InlineData(OrderSideEnum.Buy, 5.0, 10.0, 15.0, "GreaterThanOrEqualValidator", "GreaterThanOrEqualValidator")]
- //[InlineData(OrderSideEnum.Sell, 15.0, 10.0, 5.0, "LessThanOrEqualValidator", "LessThanOrEqualValidator")]
- //public void ValidateOrdersWithIncorrectStopLimitPrice(
- // OrderSideEnum orderSide,
- // double? orderPrice,
- // double? activationPrice,
- // double? price,
- // string activationError,
- // string orderError)
- //{
- // var order = GenerateOrder(AssetX, orderSide, OrderTypeEnum.StopLimit, 1.0, price, price, activationPrice, orderPrice);
- // var errors = base.ValidateOrders(order).Select(o => $"{o.PropertyName} {o.ErrorCode}");
-
- // Assert.Contains($"{nameof(order.ActivationPrice)} {activationError}", errors);
- // Assert.Contains($"{nameof(order.Transaction.Price)} {orderError}", errors);
- //}
-
- //[Fact]
- //public void CreateOrdersWithEmptyOrder()
- //{
- // var order = new OrderModel();
-
- // base.CreateOrders(order);
-
- // Assert.Empty(Account.Orders);
- // Assert.Empty(Account.Positions);
- // Assert.Empty(Account.ActiveOrders);
- // Assert.Empty(Account.ActivePositions);
- // Assert.Null(order.Transaction.Status);
- //}
-
- //[Theory]
- //[InlineData(OrderSideEnum.Buy, OrderTypeEnum.Market, 5.0, null, null, 1, 0, 0, 1)]
- //[InlineData(OrderSideEnum.Sell, OrderTypeEnum.Market, 5.0, null, null, 1, 0, 0, 1)]
- //[InlineData(OrderSideEnum.Buy, OrderTypeEnum.Stop, 5.0, null, 15.0, 1, 1, 0, 0)]
- //[InlineData(OrderSideEnum.Sell, OrderTypeEnum.Stop, 15.0, null, 5.0, 1, 1, 0, 0)]
- //[InlineData(OrderSideEnum.Buy, OrderTypeEnum.Limit, 15.0, null, 5.0, 1, 1, 0, 0)]
- //[InlineData(OrderSideEnum.Sell, OrderTypeEnum.Limit, 5.0, null, 15.0, 1, 1, 0, 0)]
- //[InlineData(OrderSideEnum.Buy, OrderTypeEnum.StopLimit, 5.0, 10.0, 15.0, 1, 1, 0, 0)]
- //[InlineData(OrderSideEnum.Sell, OrderTypeEnum.StopLimit, 15.0, 10.0, 5.0, 1, 1, 0, 0)]
- //public void CreateOrdersWithoutMatching(
- // OrderSideEnum orderSide,
- // OrderTypeEnum orderType,
- // double? price,
- // double? activationPrice,
- // double? orderPrice,
- // int orders,
- // int activeOrders,
- // int positions,
- // int activePositions)
- //{
- // var order = GenerateOrder(AssetX, orderSide, orderType, 1.0, price, price, activationPrice, orderPrice);
-
- // base.CreateOrders(order);
-
- // Assert.Equal(orders, Account.Orders.Count);
- // Assert.Equal(activeOrders, Account.ActiveOrders.Count);
- // Assert.Equal(positions, Account.Positions.Count);
- // Assert.Equal(activePositions, Account.ActivePositions.Count);
- //}
-
- //[Theory]
- //[InlineData(OrderSideEnum.Buy, OrderTypeEnum.Stop, 15.0, null, 25.0)]
- //[InlineData(OrderSideEnum.Sell, OrderTypeEnum.Stop, 15.0, null, 5.0)]
- //[InlineData(OrderSideEnum.Buy, OrderTypeEnum.Limit, 15.0, null, 5.0)]
- //[InlineData(OrderSideEnum.Sell, OrderTypeEnum.Limit, 15.0, null, 25.0)]
- //[InlineData(OrderSideEnum.Buy, OrderTypeEnum.StopLimit, 15.0, 20.0, 25.0)]
- //[InlineData(OrderSideEnum.Sell, OrderTypeEnum.StopLimit, 15.0, 10.0, 5.0)]
- //public void SendPendingOrderUpdatingStatements(
- // OrderSideEnum orderSide,
- // OrderTypeEnum orderType,
- // double? price,
- // double? activationPrice,
- // double? orderPrice)
- //{
- // var order = GenerateOrder(AssetX, orderSide, orderType, 1.0, price, price, activationPrice, orderPrice);
- // var orderId = order.Transaction.Descriptor.Id;
-
- // base.SendPendingOrder(order);
-
- // Assert.Equal(order.Transaction.Status, OrderStatusEnum.Placed);
- // Assert.Equal(order, Account.Orders[0]);
- // Assert.Equal(order, Account.ActiveOrders[orderId]);
- // Assert.Single(Account.Orders);
- // Assert.Single(Account.ActiveOrders);
- // Assert.Empty(Account.Positions);
- // Assert.Empty(Account.ActivePositions);
- //}
-
- //[Theory]
- //[InlineData(OrderSideEnum.Buy, OrderTypeEnum.Market, 10.0, 15.0, 15.0)]
- //[InlineData(OrderSideEnum.Sell, OrderTypeEnum.Market, 10.0, 15.0, 10.0)]
- //public void CreatePositionWithoutMatching(
- // OrderSideEnum orderSide,
- // OrderTypeEnum orderType,
- // double? bid,
- // double? ask,
- // double? price)
- //{
- // var order = GenerateOrder(AssetX, orderSide, orderType, 1.0, bid, ask, null, null);
- // var point = order.Transaction.Instrument.Points.First();
- // var orderId = order.Transaction.Descriptor.Id;
-
- // base.CreatePosition(order);
-
- // var position = Account.ActivePositions[orderId];
- // var openPrice = position.Orders.First();
- // var closePrice = position.Orders.Last();
-
- // Assert.Equal(order.Transaction.Price, price);
- // Assert.Equal(order.Transaction.Status, OrderStatusEnum.Filled);
-
- // Assert.Equal(position.Order.Transaction.Time, order.Transaction.Time);
- // Assert.Equal(position.Order.Transaction.Price, price);
- // Assert.Equal(openPrice.Transaction.Price, price);
- // Assert.Equal(closePrice.Transaction.Price, price);
- // Assert.Single(position.Orders);
-
- // Assert.Equal(order, Account.Orders[0]);
- // Assert.Equal(orderId, Account.ActivePositions[orderId].Order.Transaction.Descriptor.Id);
- // Assert.Empty(Account.Positions);
- // Assert.Empty(Account.ActiveOrders);
- // Assert.Single(Account.Orders);
- // Assert.Single(Account.ActivePositions);
- //}
-
- //[Fact]
- //public void CreatePositionWithPendingOrders()
- //{
- // var price = 15.0;
- // var order = GenerateOrder(AssetX, OrderSideEnum.Buy, OrderTypeEnum.Market, 1.0, price, price, null, null);
- // var SL = GenerateOrder(AssetX, OrderSideEnum.Sell, OrderTypeEnum.Stop, 1.0, price, price, null, 5.0);
- // var TP = GenerateOrder(AssetX, OrderSideEnum.Sell, OrderTypeEnum.Limit, 1.0, price, price, null, 25.0);
- // var orderId = order.Transaction.Descriptor.Id;
-
- // order.Orders.Add(SL);
- // order.Orders.Add(TP);
-
- // var position = base.CreatePosition(order);
-
- // Assert.Empty(Account.Positions);
- // Assert.Empty(Account.ActiveOrders);
- // Assert.Single(Account.Orders);
- // Assert.Single(Account.ActivePositions);
- // Assert.Equal(order, Account.Orders[0]);
- // Assert.Equal(orderId, Account.ActivePositions[orderId].Order.Transaction.Descriptor.Id);
- // Assert.Equal(position, Account.ActivePositions[orderId]);
- //}
-
- //[Fact]
- //public void GetPositionFromOrder()
- //{
- // var SL = GenerateOrder(AssetX, OrderSideEnum.Sell, OrderTypeEnum.Stop, 2.0, 15.0, 15.0, 5.0, null);
- // var order = GenerateOrder(AssetX, OrderSideEnum.Buy, OrderTypeEnum.Stop, 1.0, 15.0, 15.0, null, 25.0);
- // var orderId = order.Transaction.Descriptor.Id;
-
- // order.Orders.Add(SL);
-
- // var response = base.GetPosition(order);
-
- // Assert.Equal(orderId, response.Order.Transaction.Descriptor.Id);
- // Assert.Equal(order.Transaction.Descriptor.Name, response.Order.Transaction.Descriptor.Name);
- // Assert.Equal(order.Transaction.Descriptor.Description, response.Order.Transaction.Descriptor.Description);
- // Assert.Equal(order.Transaction.Descriptor.Group, response.Order.Transaction.Descriptor.Group);
- // Assert.Equal(order.Type, response.Order.Type);
- // Assert.Equal(order.Side, response.Order.Side);
- // Assert.Equal(order.Transaction.Volume, response.Order.Transaction.Volume);
- // Assert.Equal(order.Transaction.Price, response.Order.Transaction.Price);
- // Assert.Equal(order.Transaction.Instrument, response.Order.Transaction.Instrument);
- // Assert.Equal(order.ActivationPrice, response.Order.ActivationPrice);
- // Assert.Equal(order.Orders, response.Orders);
- //}
-
- //[Fact]
- //public void UpdateOrdersWithMatches()
- //{
- // var SL = GenerateOrder(AssetX, OrderSideEnum.Sell, OrderTypeEnum.Stop, 2.0, 15.0, 15.0, 5.0, null);
- // var order = GenerateOrder(AssetX, OrderSideEnum.Buy, OrderTypeEnum.StopLimit, 2.0, 5.0, 5.0, 10.0, 15.0);
- // var orderX = GenerateOrder(AssetX, OrderSideEnum.Buy, OrderTypeEnum.Stop, 1.0, 15.0, 15.0, null, 25.0);
- // var orderY = GenerateOrder(AssetX, OrderSideEnum.Sell, OrderTypeEnum.Stop, 1.0, 15.0, 15.0, null, 5.0);
-
- // order.Transaction.Descriptor.Id = orderY.Transaction.Descriptor.Id;
- // order.Orders.Add(SL);
-
- // var orderId = order.Transaction.Descriptor.Id;
- // var orderIdX = orderX.Transaction.Descriptor.Id;
- // var orderIdY = orderY.Transaction.Descriptor.Id;
-
- // Account.ActiveOrders.Add(orderIdX, orderX);
- // Account.ActiveOrders.Add(orderIdY, orderY);
-
- // base.UpdateOrders(order);
-
- // var update = Account.ActiveOrders[orderIdY];
-
- // Assert.Equal(2, Account.ActiveOrders.Count);
- // Assert.Equal(orderIdY, Account.ActiveOrders[orderIdY].Transaction.Descriptor.Id);
- // Assert.Equal(orderIdX, Account.ActiveOrders[orderIdX].Transaction.Descriptor.Id);
- // Assert.Equal(orderId, update.Transaction.Descriptor.Id);
- // Assert.Equal(order.Transaction.Descriptor.Name, update.Transaction.Descriptor.Name);
- // Assert.Equal(order.Transaction.Descriptor.Description, update.Transaction.Descriptor.Description);
- // Assert.Equal(order.Transaction.Descriptor.Group, update.Transaction.Descriptor.Group);
- // Assert.Equal(order.Type, update.Type);
- // Assert.Equal(order.Side, update.Side);
- // Assert.Equal(order.Transaction.Volume, update.Transaction.Volume);
- // Assert.Equal(order.Transaction.Price, update.Transaction.Price);
- // Assert.Equal(order.Transaction.Instrument, update.Transaction.Instrument);
- // Assert.Equal(order.ActivationPrice, update.ActivationPrice);
- // Assert.Equal(order.Orders, update.Orders);
- // Assert.Empty(Account.ActivePositions);
- // Assert.Empty(Account.Positions);
- // Assert.Empty(Account.Orders);
- //}
-
- //[Fact]
- //public void IncreasePositionWithMatches()
- //{
- // var instrumentX = Account.Instruments[AssetX];
- // var instrumentY = Account.Instruments[AssetY];
- // var pointX = instrumentX.Points.Last();
- // var pointY = instrumentY.Points.Last();
- // var orderX = GenerateOrder(AssetX, OrderSideEnum.Buy, OrderTypeEnum.Market, 1, pointX.Bid, pointX.Ask, null, null);
- // var orderY = GenerateOrder(AssetY, OrderSideEnum.Buy, OrderTypeEnum.Market, 2, pointY.Bid, pointY.Ask, null, null);
- // var increase = GenerateOrder(AssetY, OrderSideEnum.Buy, OrderTypeEnum.Market, 3, pointY.Bid + 5, pointY.Ask + 5, null, null);
-
- // // Open
-
- // base.CreateOrders(orderX);
- // base.CreateOrders(orderY);
-
- // // Increase
-
- // var previousPosition = Account.ActivePositions[orderY.Transaction.Descriptor.Id];
- // var nextPosition = base.IncreasePosition(increase, previousPosition);
- // var averageTradePrice = nextPosition.Order.Orders.Sum(o => o.Transaction.Volume * o.Transaction.Price) / nextPosition.Orders.Sum(o => o.Transaction.Volume);
-
- // Assert.Equal(3, Account.Orders.Count);
- // Assert.Equal(0, Account.ActiveOrders.Count);
- // Assert.Equal(2, Account.ActivePositions.Count);
- // Assert.Empty(Account.Positions);
-
- // var openA = nextPosition.Orders[0];
- // var openB = nextPosition.Orders[1];
-
- // Assert.Equal(orderY.Transaction.Volume, openA.Transaction.Volume);
- // Assert.Equal(increase.Transaction.Volume, openB.Transaction.Volume);
- // Assert.Equal(pointY.Ask, openA.Transaction.Price);
- // Assert.Equal(pointY.Ask + 5, openB.Transaction.Price);
- // Assert.Equal(orderY.Transaction.Time, openA.Transaction.Time);
- // Assert.Equal(increase.Transaction.Time, openB.Transaction.Time);
- // Assert.Equal(2, nextPosition.Orders.Count);
-
- // Assert.Equal(increase.Transaction.Descriptor.Id, nextPosition.Order.Transaction.Descriptor.Id);
- // Assert.Equal(increase.Transaction.Time, nextPosition.Order.Transaction.Time);
- // Assert.Equal(averageTradePrice, nextPosition.Order.Transaction.Price);
- // Assert.Equal(increase.Transaction.Volume + orderY.Transaction.Volume, nextPosition.Order.Transaction.Volume);
-
- // Assert.Equal(nextPosition.Order.Transaction.Time, previousPosition.Order.Transaction.Time);
- // Assert.Equal(openB.Transaction.Price, previousPosition.Order.Transaction.Price);
- // Assert.Equal(previousPosition.GainLossEstimate, previousPosition.GainLoss);
- // Assert.Equal(previousPosition.GainLossPointsEstimate, previousPosition.GainLossPoints);
-
- // // Estimate
-
- // var step = instrumentY.StepValue / instrumentY.StepSize;
- // var priceUpdate = new PointModel { Ask = 50, Bid = 40, Last = 40, Instrument = instrumentY };
-
- // instrumentY.Points.Add(priceUpdate);
- // instrumentY.PointGroups.Add(priceUpdate);
-
- // nextPosition.Order.Transaction.Instrument = instrumentY;
-
- // Assert.Equal(nextPosition.GainLossPointsEstimate * nextPosition.Order.Transaction.Volume * step - instrumentY.Commission, nextPosition.GainLossEstimate);
- // Assert.Equal(priceUpdate.Bid - nextPosition.Order.Transaction.Price, nextPosition.GainLossPointsEstimate);
- //}
-
- //[Fact]
- //public void DecreasePositionWithMatches()
- //{
- // var instrumentX = Account.Instruments[AssetX];
- // var instrumentY = Account.Instruments[AssetY];
- // var pointX = instrumentX.Points.Last();
- // var pointY = instrumentY.Points.Last();
- // var orderX = GenerateOrder(AssetX, OrderSideEnum.Buy, OrderTypeEnum.Market, 1, pointX.Bid, pointX.Ask, null, null);
- // var orderY = GenerateOrder(AssetY, OrderSideEnum.Buy, OrderTypeEnum.Market, 1, pointY.Bid, pointY.Ask, null, null);
- // var decreaseA = GenerateOrder(AssetY, OrderSideEnum.Sell, OrderTypeEnum.Market, 2, pointY.Bid + 5, pointY.Ask + 5, null, null);
- // var decreaseB = GenerateOrder(AssetY, OrderSideEnum.Buy, OrderTypeEnum.Market, 1, pointY.Bid + 15, pointY.Ask + 15, null, null);
-
- // // Open
-
- // base.CreateOrders(orderX);
- // base.CreateOrders(orderY);
-
- // // Inverse
-
- // var previousPosition = Account.ActivePositions[orderY.Transaction.Descriptor.Id];
- // var nextPosition = base.DecreasePosition(decreaseA, previousPosition);
-
- // Assert.Equal(3, Account.Orders.Count);
- // Assert.Equal(0, Account.ActiveOrders.Count);
- // Assert.Equal(2, Account.ActivePositions.Count);
- // Assert.Single(Account.Positions);
-
- // var openA = nextPosition.Orders[0];
-
- // Assert.Equal(decreaseA.Transaction.Volume, openA.Transaction.Volume);
- // Assert.Equal(pointY.Bid + 5, openA.Transaction.Price);
- // Assert.Equal(decreaseA.Transaction.Time, openA.Transaction.Time);
- // Assert.Single(nextPosition.Orders);
-
- // Assert.Equal(decreaseA.Transaction.Descriptor.Id, nextPosition.Order.Transaction.Descriptor.Id);
- // Assert.Equal(decreaseA.Transaction.Time, nextPosition.Order.Transaction.Time);
- // Assert.Equal(openA.Transaction.Price, nextPosition.Order.Transaction.Price);
- // Assert.Equal(Math.Abs(orderY.Transaction.Volume.Value - decreaseA.Transaction.Volume.Value), nextPosition.Order.Transaction.Volume);
-
- // Assert.Equal(nextPosition.Order.Transaction.Time, previousPosition.Order.Transaction.Time);
- // Assert.Equal(openA.Transaction.Price, previousPosition.Order.Transaction.Price);
- // Assert.Equal(previousPosition.GainLossEstimate, previousPosition.GainLoss);
- // Assert.Equal(previousPosition.GainLossPointsEstimate, previousPosition.GainLossPoints);
-
- // // Close
-
- // previousPosition = Account.ActivePositions[decreaseA.Transaction.Descriptor.Id];
- // nextPosition = base.DecreasePosition(decreaseB, previousPosition);
-
- // Assert.Equal(4, Account.Orders.Count);
- // Assert.Equal(0, Account.ActiveOrders.Count);
- // Assert.Equal(2, Account.Positions.Count);
- // Assert.Equal(1, Account.ActivePositions.Count);
- //}
}
}
diff --git a/Gateways/Simulation/Tests/CreateOrders.cs b/Gateways/Simulation/Tests/CreateOrders.cs
index 8b76a3c61..b298b6e5f 100644
--- a/Gateways/Simulation/Tests/CreateOrders.cs
+++ b/Gateways/Simulation/Tests/CreateOrders.cs
@@ -1,5 +1,5 @@
using System;
-using Terminal.Connector.Simulation;
+using Simulation;
using Terminal.Core.Collections;
using Terminal.Core.Domains;
using Terminal.Core.Enums;
diff --git a/Gateways/Simulation/Tests/CreatePosition.cs b/Gateways/Simulation/Tests/CreatePosition.cs
index 0f3047498..ae0d78380 100644
--- a/Gateways/Simulation/Tests/CreatePosition.cs
+++ b/Gateways/Simulation/Tests/CreatePosition.cs
@@ -1,6 +1,6 @@
using System;
using System.Linq;
-using Terminal.Connector.Simulation;
+using Simulation;
using Terminal.Core.Collections;
using Terminal.Core.Domains;
using Terminal.Core.Enums;
diff --git a/Gateways/Simulation/Tests/DecreasePosition.cs b/Gateways/Simulation/Tests/DecreasePosition.cs
index abbe9bb66..1b448f57d 100644
--- a/Gateways/Simulation/Tests/DecreasePosition.cs
+++ b/Gateways/Simulation/Tests/DecreasePosition.cs
@@ -1,6 +1,6 @@
using System;
using System.Linq;
-using Terminal.Connector.Simulation;
+using Simulation;
using Terminal.Core.Collections;
using Terminal.Core.Domains;
using Terminal.Core.Enums;
@@ -35,8 +35,8 @@ public void Decrease()
var nextPosition = base.DecreasePosition(order, previousPosition);
Assert.Single(Account.Positions);
+ Assert.Empty(Account.ActiveOrders);
Assert.Equal(3, Account.Orders.Count);
- Assert.Equal(0, Account.ActiveOrders.Count);
Assert.Equal(2, Account.ActivePositions.Count);
Assert.Equal(2, nextPosition.Orders.Count);
@@ -87,9 +87,9 @@ public void Close()
var nextPosition = base.DecreasePosition(order, previousPosition);
Assert.Single(Account.Positions);
+ Assert.Single(Account.ActivePositions);
Assert.Equal(3, Account.Orders.Count);
- Assert.Equal(0, Account.ActiveOrders.Count);
- Assert.Equal(1, Account.ActivePositions.Count);
+ Assert.Empty(Account.ActiveOrders);
Assert.Equal(2, nextPosition.Orders.Count);
// Order #1
@@ -139,8 +139,8 @@ public void Inverse()
var nextPosition = base.DecreasePosition(order, previousPosition);
Assert.Single(Account.Positions);
+ Assert.Empty(Account.ActiveOrders);
Assert.Equal(3, Account.Orders.Count);
- Assert.Equal(0, Account.ActiveOrders.Count);
Assert.Equal(2, Account.ActivePositions.Count);
Assert.Equal(2, nextPosition.Orders.Count);
diff --git a/Gateways/Simulation/Tests/IncreasePosition.cs b/Gateways/Simulation/Tests/IncreasePosition.cs
index 48a601178..7a9d09592 100644
--- a/Gateways/Simulation/Tests/IncreasePosition.cs
+++ b/Gateways/Simulation/Tests/IncreasePosition.cs
@@ -1,6 +1,6 @@
using System;
using System.Linq;
-using Terminal.Connector.Simulation;
+using Simulation;
using Terminal.Core.Collections;
using Terminal.Core.Domains;
using Terminal.Core.Enums;
@@ -42,8 +42,8 @@ public void Increase()
// State
Assert.Empty(Account.Positions);
+ Assert.Empty(Account.ActiveOrders);
Assert.Equal(3, Account.Orders.Count);
- Assert.Equal(0, Account.ActiveOrders.Count);
Assert.Equal(2, Account.ActivePositions.Count);
Assert.Equal(2, nextPosition.Orders.Count);
diff --git a/Gateways/Simulation/Tests/SendPendingOrder.cs b/Gateways/Simulation/Tests/SendPendingOrder.cs
index 102c3ffb7..2932cf40c 100644
--- a/Gateways/Simulation/Tests/SendPendingOrder.cs
+++ b/Gateways/Simulation/Tests/SendPendingOrder.cs
@@ -1,5 +1,5 @@
using System;
-using Terminal.Connector.Simulation;
+using Simulation;
using Terminal.Core.Collections;
using Terminal.Core.Domains;
using Terminal.Core.Enums;
diff --git a/Gateways/Simulation/Tests/Terminal.Tests.csproj b/Gateways/Simulation/Tests/Terminal.Tests.csproj
deleted file mode 100644
index de9b75f60..000000000
--- a/Gateways/Simulation/Tests/Terminal.Tests.csproj
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- net7.0
- disable
- disable
- false
-
-
-
-
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
-
-
-
-
-
-
diff --git a/Gateways/Simulation/Tests/UpdateOrders.cs b/Gateways/Simulation/Tests/UpdateOrders.cs
index b225bf10f..29dcb49cf 100644
--- a/Gateways/Simulation/Tests/UpdateOrders.cs
+++ b/Gateways/Simulation/Tests/UpdateOrders.cs
@@ -1,6 +1,6 @@
using System;
using System.Linq;
-using Terminal.Connector.Simulation;
+using Simulation;
using Terminal.Core.Collections;
using Terminal.Core.Domains;
using Terminal.Core.Enums;
diff --git a/Gateways/Simulation/Tests/ValidateOrders.cs b/Gateways/Simulation/Tests/ValidateOrders.cs
index 9bf47b024..beefc43e8 100644
--- a/Gateways/Simulation/Tests/ValidateOrders.cs
+++ b/Gateways/Simulation/Tests/ValidateOrders.cs
@@ -1,8 +1,7 @@
-using FluentValidation.Results;
+using Simulation;
using System;
using System.Collections.Generic;
using System.Linq;
-using Terminal.Connector.Simulation;
using Terminal.Core.Collections;
using Terminal.Core.Domains;
using Terminal.Core.Enums;
diff --git a/Gateways/Tda/Libs/Adapter.cs b/Gateways/Tda/Libs/Adapter.cs
deleted file mode 100644
index 48b53d991..000000000
--- a/Gateways/Tda/Libs/Adapter.cs
+++ /dev/null
@@ -1,255 +0,0 @@
-using ServiceScheduler;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net.Http;
-using System.Reactive.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Terminal.Connector.Tda.Models;
-using Terminal.Core.Enums;
-using Terminal.Core.Extensions;
-using Terminal.Core.Models;
-using Terminal.Core.Services;
-
-namespace Terminal.Connector.Tda
-{
- public class Adapter : Terminal.Core.Domains.Connector
- {
- ///
- /// User
- ///
- protected UserModel _user;
-
- ///
- /// Disposable connections
- ///
- protected IList _connections;
-
- ///
- /// Disposable subscriptions
- ///
- protected IList _subscriptions;
-
- ///
- /// Application ID
- ///
- public virtual string ConsumerKey { get; set; }
-
- ///
- /// Username
- ///
- public virtual string Username { get; set; }
-
- ///
- /// Password
- ///
- public virtual string Password { get; set; }
-
- ///
- /// Answer to a secret question
- ///
- public virtual string Answer { get; set; }
-
- ///
- /// Query URL
- ///
- public virtual string QueryUri { get; set; } = "https://api.tdameritrade.com/v1";
-
- ///
- /// Authentication URL
- ///
- public virtual string SignInRemoteUri { get; set; } = "https://auth.tdameritrade.com/auth";
-
- ///
- /// Authentication URL for API
- ///
- public virtual string SignInApiUri { get; set; } = "https://api.tdameritrade.com/v1/oauth2/token";
-
- ///
- /// Local return URL for authentication
- ///
- public virtual string SignInLocalUri { get; set; } = "http://localhost";
-
- ///
- /// Constructor
- ///
- public Adapter()
- {
- _connections = new List();
- _subscriptions = new List();
- }
-
- ///
- /// Connect
- ///
- public override async Task> Connect()
- {
- await Disconnect();
-
- var automator = new Authenticator
- {
- Location = Path.GetTempPath()
- };
-
- _user = await automator.SignIn(this);
-
- await Subscribe();
-
- return null;
- }
-
- ///
- /// Subscribe to data streams
- ///
- public override async Task> Subscribe()
- {
- await Unsubscribe();
-
- return null;
- }
-
- ///
- /// Save state and dispose
- ///
- public override Task> Disconnect()
- {
- Unsubscribe();
-
- _connections?.ForEach(o => o.Dispose());
- _connections?.Clear();
-
- return Task.FromResult>(null);
- }
-
- ///
- /// Unsubscribe from data streams
- ///
- public override Task> Unsubscribe()
- {
- _subscriptions?.ForEach(o => o.Dispose());
- _subscriptions?.Clear();
-
- return Task.FromResult>(null);
- }
-
- ///
- /// Get quote
- ///
- ///
- public override Task> GetPoint(PointMessageModel message)
- {
- var response = new ResponseItemModel
- {
- Data = Account.Instruments[message.Name].Points.LastOrDefault()
- };
-
- return Task.FromResult(response);
- }
-
- ///
- /// Get option chains
- ///
- ///
- public override async Task>> GetOptions(OptionMessageModel message)
- {
- var props = new Dictionary