Production hardening: kill switch, circuit breaker, trailing stops, log level, holiday calendar
Some checks failed
Build and Test / build (push) Has been cancelled
Some checks failed
Build and Test / build (push) Has been cancelled
This commit is contained in:
245
tests/NT8.Core.Tests/Adapters/NT8ExecutionAdapterTests.cs
Normal file
245
tests/NT8.Core.Tests/Adapters/NT8ExecutionAdapterTests.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using NT8.Adapters.NinjaTrader;
|
||||
using NT8.Core.OMS;
|
||||
|
||||
namespace NT8.Core.Tests.Adapters
|
||||
{
|
||||
/// <summary>
|
||||
/// Unit tests for NT8ExecutionAdapter.
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public class NT8ExecutionAdapterTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void SubmitOrder_WithValidRequest_ShouldCreateTrackingInfo()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
var request = CreateRequest();
|
||||
|
||||
var info = adapter.SubmitOrder(request, "SDK-1");
|
||||
|
||||
Assert.IsNotNull(info);
|
||||
Assert.AreEqual("SDK-1", info.SdkOrderId);
|
||||
Assert.AreEqual(OrderState.Pending, info.CurrentState);
|
||||
Assert.AreEqual(0, info.FilledQuantity);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SubmitOrder_WithDuplicateOrderId_ShouldThrowInvalidOperationException()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(), "SDK-1");
|
||||
|
||||
Assert.ThrowsException<InvalidOperationException>(
|
||||
delegate
|
||||
{
|
||||
adapter.SubmitOrder(CreateRequest(), "SDK-1");
|
||||
});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SubmitOrder_WithNullRequest_ShouldThrowArgumentNullException()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
|
||||
Assert.ThrowsException<ArgumentNullException>(
|
||||
delegate
|
||||
{
|
||||
adapter.SubmitOrder(null, "SDK-1");
|
||||
});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessOrderUpdate_WithWorkingState_ShouldUpdateState()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(), "SDK-1");
|
||||
|
||||
adapter.ProcessOrderUpdate("NT8-1", "SDK-1", "WORKING", 0, 0.0, 0, null);
|
||||
|
||||
var status = adapter.GetOrderStatus("SDK-1");
|
||||
Assert.IsNotNull(status);
|
||||
Assert.AreEqual(OrderState.Working, status.State);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessOrderUpdate_WithFilledState_ShouldMarkFilled()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(2), "SDK-1");
|
||||
|
||||
adapter.ProcessOrderUpdate("NT8-1", "SDK-1", "FILLED", 2, 4205.25, 0, null);
|
||||
|
||||
var status = adapter.GetOrderStatus("SDK-1");
|
||||
Assert.AreEqual(OrderState.Filled, status.State);
|
||||
Assert.AreEqual(2, status.FilledQuantity);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessOrderUpdate_WithRejection_ShouldSetRejectedState()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(), "SDK-1");
|
||||
|
||||
adapter.ProcessOrderUpdate("NT8-1", "SDK-1", "WORKING", 0, 0.0, 123, "Rejected by broker");
|
||||
|
||||
var status = adapter.GetOrderStatus("SDK-1");
|
||||
Assert.AreEqual(OrderState.Rejected, status.State);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessExecution_WithFullFill_ShouldMarkFilled()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(3), "SDK-1");
|
||||
adapter.ProcessOrderUpdate("NT8-1", "SDK-1", "PARTFILLED", 3, 4202.0, 0, null);
|
||||
|
||||
adapter.ProcessExecution("NT8-1", "EX-1", 4202.0, 3, DateTime.UtcNow);
|
||||
|
||||
var status = adapter.GetOrderStatus("SDK-1");
|
||||
Assert.AreEqual(OrderState.Filled, status.State);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessExecution_WithPartialFill_ShouldMarkPartiallyFilled()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(3), "SDK-1");
|
||||
adapter.ProcessOrderUpdate("NT8-1", "SDK-1", "PARTFILLED", 1, 4202.0, 0, null);
|
||||
|
||||
adapter.ProcessExecution("NT8-1", "EX-1", 4202.0, 1, DateTime.UtcNow);
|
||||
|
||||
var status = adapter.GetOrderStatus("SDK-1");
|
||||
Assert.AreEqual(OrderState.PartiallyFilled, status.State);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CancelOrder_WithWorkingOrder_ShouldReturnTrue()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(), "SDK-1");
|
||||
adapter.ProcessOrderUpdate("NT8-1", "SDK-1", "WORKING", 0, 0.0, 0, null);
|
||||
|
||||
var result = adapter.CancelOrder("SDK-1");
|
||||
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CancelOrder_WithFilledOrder_ShouldReturnFalse()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(), "SDK-1");
|
||||
adapter.ProcessOrderUpdate("NT8-1", "SDK-1", "FILLED", 1, 4202.0, 0, null);
|
||||
|
||||
var result = adapter.CancelOrder("SDK-1");
|
||||
|
||||
Assert.IsFalse(result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetOrderStatus_WithExistingOrder_ShouldReturnStatus()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(), "SDK-1");
|
||||
|
||||
var status = adapter.GetOrderStatus("SDK-1");
|
||||
|
||||
Assert.IsNotNull(status);
|
||||
Assert.AreEqual("SDK-1", status.OrderId);
|
||||
Assert.AreEqual("ES", status.Symbol);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetOrderStatus_WithNonExistentOrder_ShouldReturnNull()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
|
||||
var status = adapter.GetOrderStatus("MISSING");
|
||||
|
||||
Assert.IsNull(status);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow("ACCEPTED", OrderState.Working)]
|
||||
[DataRow("FILLED", OrderState.Filled)]
|
||||
[DataRow("CANCELLED", OrderState.Cancelled)]
|
||||
[DataRow("REJECTED", OrderState.Rejected)]
|
||||
public void MapNT8OrderState_WithKnownStates_ShouldMapCorrectly(string nt8State, OrderState expected)
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(), "SDK-1");
|
||||
|
||||
adapter.ProcessOrderUpdate("NT8-1", "SDK-1", nt8State, 0, 0.0, 0, null);
|
||||
|
||||
var status = adapter.GetOrderStatus("SDK-1");
|
||||
Assert.AreEqual(expected, status.State);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SubmitOrder_WithConcurrentCalls_ShouldBeThreadSafe()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
var tasks = new List<Task>();
|
||||
var count = 50;
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var index = i;
|
||||
tasks.Add(Task.Run(
|
||||
delegate
|
||||
{
|
||||
adapter.SubmitOrder(CreateRequest(), string.Format("SDK-{0}", index));
|
||||
}));
|
||||
}
|
||||
|
||||
Task.WaitAll(tasks.ToArray());
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var status = adapter.GetOrderStatus(string.Format("SDK-{0}", i));
|
||||
Assert.IsNotNull(status);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessExecution_WithMultipleCallsForSameOrder_ShouldAccumulate()
|
||||
{
|
||||
var adapter = new NT8ExecutionAdapter();
|
||||
adapter.SubmitOrder(CreateRequest(3), "SDK-1");
|
||||
|
||||
adapter.ProcessOrderUpdate("NT8-1", "SDK-1", "PARTFILLED", 1, 4201.0, 0, null);
|
||||
adapter.ProcessExecution("NT8-1", "EX-1", 4201.0, 1, DateTime.UtcNow);
|
||||
|
||||
var statusAfterFirst = adapter.GetOrderStatus("SDK-1");
|
||||
Assert.AreEqual(OrderState.PartiallyFilled, statusAfterFirst.State);
|
||||
|
||||
adapter.ProcessOrderUpdate("NT8-1", "SDK-1", "FILLED", 3, 4202.0, 0, null);
|
||||
adapter.ProcessExecution("NT8-1", "EX-2", 4202.0, 2, DateTime.UtcNow);
|
||||
|
||||
var statusAfterSecond = adapter.GetOrderStatus("SDK-1");
|
||||
Assert.AreEqual(OrderState.Filled, statusAfterSecond.State);
|
||||
Assert.AreEqual(3, statusAfterSecond.FilledQuantity);
|
||||
}
|
||||
|
||||
private static OrderRequest CreateRequest()
|
||||
{
|
||||
return CreateRequest(1);
|
||||
}
|
||||
|
||||
private static OrderRequest CreateRequest(int quantity)
|
||||
{
|
||||
var request = new OrderRequest();
|
||||
request.Symbol = "ES";
|
||||
request.Side = OrderSide.Buy;
|
||||
request.Type = OrderType.Market;
|
||||
request.Quantity = quantity;
|
||||
request.TimeInForce = TimeInForce.Day;
|
||||
request.ClientOrderId = Guid.NewGuid().ToString();
|
||||
return request;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user