Files
2026-07-13 13:02:50 +08:00

823 lines
28 KiB
C#

/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using NUnit.Framework;
using QuantConnect.Orders;
using QuantConnect.Orders.TimeInForces;
namespace QuantConnect.Tests.Common.Orders
{
[TestFixture]
public class OrderJsonConverterTests
{
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesMarketOrder(Symbols.SymbolsKey key)
{
var expected = new MarketOrder(Symbols.Lookup(key), 100, new DateTime(2015, 11, 23, 17, 15, 37), "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123456,
BrokerId = new List<string> {"727", "54970"}
};
TestOrderType(expected);
}
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesComboMarketOrder(Symbols.SymbolsKey key)
{
var groupOrderManager = new GroupOrderManager(1, 2, 10);
groupOrderManager.OrderIds.Add(12345);
groupOrderManager.OrderIds.Add(12346);
var expected = new ComboMarketOrder(Symbols.Lookup(key), 100, new DateTime(2015, 11, 23, 17, 15, 37), groupOrderManager, "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123457,
BrokerId = new List<string> { "727", "54970" }
};
TestOrderType(expected);
}
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesComboLimitOrder(Symbols.SymbolsKey key)
{
var groupOrderManager = new GroupOrderManager(1, 2, 10);
groupOrderManager.OrderIds.Add(12345);
groupOrderManager.OrderIds.Add(12346);
groupOrderManager.LimitPrice = 201.1m;
var expected = new ComboLimitOrder(Symbols.Lookup(key), 100, 210.1m, new DateTime(2015, 11, 23, 17, 15, 37), groupOrderManager, "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123457,
BrokerId = new List<string> { "727", "54970" }
};
TestOrderType(expected);
}
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesComboLegLimitOrder(Symbols.SymbolsKey key)
{
var groupOrderManager = new GroupOrderManager(1, 2, 10);
groupOrderManager.OrderIds.Add(12345);
groupOrderManager.OrderIds.Add(12346);
var expected = new ComboLegLimitOrder(Symbols.Lookup(key), 100, 210.1m, new DateTime(2015, 11, 23, 17, 15, 37), groupOrderManager, "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123457,
BrokerId = new List<string> { "727", "54970" }
};
TestOrderType(expected);
}
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesMarketOnOpenOrder(Symbols.SymbolsKey key)
{
var expected = new MarketOnOpenOrder(Symbols.Lookup(key), 100, new DateTime(2015, 11, 23, 17, 15, 37), "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123456,
BrokerId = new List<string> {"727", "54970"}
};
TestOrderType(expected);
}
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesMarketOnCloseOrder(Symbols.SymbolsKey key)
{
var expected = new MarketOnCloseOrder(Symbols.Lookup(key), 100, new DateTime(2015, 11, 23, 17, 15, 37), "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123456,
BrokerId = new List<string> {"727", "54970"}
};
TestOrderType(expected);
}
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesLimitOrder(Symbols.SymbolsKey key)
{
var expected = new LimitOrder(Symbols.Lookup(key), 100, 210.10m, new DateTime(2015, 11, 23, 17, 15, 37), "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123456,
BrokerId = new List<string> {"727", "54970"}
};
var actual = TestOrderType(expected);
Assert.AreEqual(expected.LimitPrice, actual.LimitPrice);
}
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesStopMarketOrder(Symbols.SymbolsKey key)
{
var expected = new StopMarketOrder(Symbols.Lookup(key), 100, 210.10m, new DateTime(2015, 11, 23, 17, 15, 37), "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123456,
BrokerId = new List<string> {"727", "54970"}
};
var actual = TestOrderType(expected);
Assert.AreEqual(expected.StopPrice, actual.StopPrice);
}
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesTrailingStopOrder(Symbols.SymbolsKey key)
{
var expected = new TrailingStopOrder(Symbols.Lookup(key), 100, 210.10m, 0.1m, true, new DateTime(2015, 11, 23, 17, 15, 37), "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123456,
BrokerId = new List<string> { "727", "54970" }
};
var actual = TestOrderType(expected);
Assert.AreEqual(expected.StopPrice, actual.StopPrice);
Assert.AreEqual(expected.TrailingAmount, actual.TrailingAmount);
Assert.AreEqual(expected.TrailingAsPercentage, actual.TrailingAsPercentage);
}
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesStopLimitOrder(Symbols.SymbolsKey key)
{
var expected = new StopLimitOrder(Symbols.Lookup(key), 100, 210.10m, 200.23m, new DateTime(2015, 11, 23, 17, 15, 37), "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123456,
BrokerId = new List<string> {"727", "54970"}
};
var actual = TestOrderType(expected);
Assert.AreEqual(expected.StopPrice, actual.StopPrice);
Assert.AreEqual(expected.LimitPrice, actual.LimitPrice);
}
[TestCase(Symbols.SymbolsKey.SPY)]
[TestCase(Symbols.SymbolsKey.EURUSD)]
[TestCase(Symbols.SymbolsKey.BTCUSD)]
public void DeserializesLimitIfTouchedOrder(Symbols.SymbolsKey key)
{
var expected = new LimitIfTouchedOrder(Symbols.Lookup(key), 100, 210.10m, 200.23m, new DateTime(2015, 11, 23, 17, 15, 37), "now")
{
Id = 12345,
Price = 209.03m,
ContingentId = 123456,
BrokerId = new List<string> {"727", "54970"}
};
var actual = TestOrderType(expected);
Assert.AreEqual(expected.TriggerPrice, actual.TriggerPrice);
Assert.AreEqual(expected.LimitPrice, actual.LimitPrice);
}
[Test]
public void DeserializesOptionExpireOrder()
{
var expected = new OptionExerciseOrder(Symbols.SPY_P_192_Feb19_2016, 100, new DateTime(2015, 11, 23, 17, 15, 37), "now")
{
Id = 12345,
ContingentId = 123456,
BrokerId = new List<string> { "727", "54970" }
};
// Note: Order price equals strike price found in Symbol object
// Price = Symbol.ID.StrikePrice
TestOrderType(expected);
}
[Test]
public void DeserializesNullLastFillTimeAndLastUpdateTime()
{
const string json = @"{
'Type': 4,
'Id': 1,
'ContingentId': 0,
'BrokerId': [
'1'
],
'Symbol': {
'Value': 'SPY',
'ID': 'SPY R735QTJ8XC9X',
'Permtick': 'SPY'
},
'Price': 321.66,
'PriceCurrency': 'USD',
'Time': '2019-12-24T14:31:00Z',
'CreatedTime': '2019-12-24T14:31:00Z',
'LastUpdateTime': '2019-12-25T14:31:00Z',
'LastFillTime': null,
'Quantity': 1.0,
'Status': 3,
'TimeInForce': {},
'Tag': '',
'Properties': {
'TimeInForce': {}
},
'SecurityType': 1,
'Direction': 0,
'AbsoluteQuantity': 1.0,
'Value': 321.66,
'OrderSubmissionData': {
'BidPrice': 321.4700,
'AskPrice': 321.4700,
'LastPrice': 321.4700
},
'IsMarketable': false
}";
const string json2 = @"{
'Type': 4,
'Id': 1,
'ContingentId': 0,
'BrokerId': [
'1'
],
'Symbol': {
'Value': 'SPY',
'ID': 'SPY R735QTJ8XC9X',
'Permtick': 'SPY'
},
'Price': 321.66,
'PriceCurrency': 'USD',
'Time': '2019-12-24T14:31:00Z',
'CreatedTime': '2019-12-24T14:31:00Z',
'LastUpdateTime': null,
'LastFillTime': '2019-12-26T14:31:00Z',
'Quantity': 1.0,
'Status': 3,
'TimeInForce': {},
'Tag': '',
'Properties': {
'TimeInForce': {}
},
'SecurityType': 1,
'Direction': 0,
'AbsoluteQuantity': 1.0,
'Value': 321.66,
'OrderSubmissionData': {
'BidPrice': 321.4700,
'AskPrice': 321.4700,
'LastPrice': 321.4700
},
'IsMarketable': false
}";
var time = DateTime.SpecifyKind(new DateTime(2019, 12, 24, 14, 31, 0), DateTimeKind.Utc);
var fillTime = DateTime.SpecifyKind(new DateTime(2019, 12, 26, 14, 31, 0), DateTimeKind.Utc);
var updateTime = DateTime.SpecifyKind(new DateTime(2019, 12, 25, 14, 31, 0), DateTimeKind.Utc);
var expected1 = new MarketOnOpenOrder(Symbol.Create("SPY", SecurityType.Equity, Market.USA), 1m, time)
{
Id = 1,
ContingentId = 0,
BrokerId = new List<string> { "1" },
Price = 321.66m,
PriceCurrency = "USD",
LastFillTime = null,
LastUpdateTime = updateTime,
Status = OrderStatus.Filled,
OrderSubmissionData = new OrderSubmissionData(321.47m, 321.47m, 321.47m),
};
var expected2 = new MarketOnOpenOrder(Symbol.Create("SPY", SecurityType.Equity, Market.USA), 1m, time)
{
Id = 1,
ContingentId = 0,
BrokerId = new List<string> { "1" },
Price = 321.66m,
PriceCurrency = "USD",
LastFillTime = updateTime,
LastUpdateTime = null,
Status = OrderStatus.Filled,
OrderSubmissionData = new OrderSubmissionData(321.47m, 321.47m, 321.47m),
};
var actual1 = (MarketOnOpenOrder)DeserializeOrder<MarketOnOpenOrder>(json);
var actual2 = (MarketOnOpenOrder)DeserializeOrder<MarketOnOpenOrder>(json2);
TestOrderType(expected1);
TestOrderType(expected2);
TestOrderType(actual1);
TestOrderType(actual2);
}
[Test]
public void DeserializesStringStatusAndNullTime()
{
const string stringStatusJson = @"{
'Type': 4,
'Id': 1,
'ContingentId': 0,
'BrokerId': [
'1'
],
'Symbol': {
'Value': 'SPY',
'ID': 'SPY R735QTJ8XC9X',
'Permtick': 'SPY'
},
'Price': 321.66,
'PriceCurrency': 'USD',
'Time': '2019-12-24T14:31:00Z',
'CreatedTime': '2019-12-24T14:31:00Z',
'LastUpdateTime': '2019-12-25T14:31:00Z',
'LastFillTime': '2019-12-26T14:31:00Z',
'Quantity': 1.0,
'Status': 'filled',
'TimeInForce': {},
'Tag': '',
'Properties': {
'TimeInForce': {}
},
'SecurityType': 1,
'Direction': 0,
'AbsoluteQuantity': 1.0,
'Value': 321.66,
'OrderSubmissionData': {
'BidPrice': 321.4700,
'AskPrice': 321.4700,
'LastPrice': 321.4700
},
'IsMarketable': false
}";
const string nullTimeJson = @"{
'Type': 4,
'Id': 1,
'ContingentId': 0,
'BrokerId': [
'1'
],
'Symbol': {
'Value': 'SPY',
'ID': 'SPY R735QTJ8XC9X',
'Permtick': 'SPY'
},
'Price': 321.66,
'PriceCurrency': 'USD',
'Time': null,
'CreatedTime': '2019-12-24T14:31:00Z',
'LastUpdateTime': '2019-12-25T14:31:00Z',
'LastFillTime': '2019-12-26T14:31:00Z',
'Quantity': 1.0,
'Status': 3,
'TimeInForce': {},
'Tag': '',
'Properties': {
'TimeInForce': {}
},
'SecurityType': 1,
'Direction': 0,
'AbsoluteQuantity': 1.0,
'Value': 321.66,
'OrderSubmissionData': {
'BidPrice': 321.4700,
'AskPrice': 321.4700,
'LastPrice': 321.4700
},
'IsMarketable': false
}";
var time = DateTime.SpecifyKind(new DateTime(2019, 12, 24, 14, 31, 0), DateTimeKind.Utc);
var fillTime = DateTime.SpecifyKind(new DateTime(2019, 12, 26, 14, 31, 0), DateTimeKind.Utc);
var updateTime = DateTime.SpecifyKind(new DateTime(2019, 12, 25, 14, 31, 0), DateTimeKind.Utc);
var expected1 = new MarketOnOpenOrder(Symbol.Create("SPY", SecurityType.Equity, Market.USA), 1m, time)
{
Id = 1,
ContingentId = 0,
BrokerId = new List<string> { "1" },
Price = 321.66m,
PriceCurrency = "USD",
LastFillTime = fillTime,
LastUpdateTime = updateTime,
Status = OrderStatus.Filled,
OrderSubmissionData = new OrderSubmissionData(321.47m, 321.47m, 321.47m),
};
var expected2 = new MarketOnOpenOrder(Symbol.Create("SPY", SecurityType.Equity, Market.USA), 1m, time)
{
Id = 1,
ContingentId = 0,
BrokerId = new List<string> { "1" },
Price = 321.66m,
PriceCurrency = "USD",
LastFillTime = fillTime,
LastUpdateTime = updateTime,
Status = OrderStatus.Filled,
OrderSubmissionData = new OrderSubmissionData(321.47m, 321.47m, 321.47m),
};
var actual1 = (MarketOnOpenOrder)DeserializeOrder<MarketOnOpenOrder>(stringStatusJson);
var actual2 = (MarketOnOpenOrder)DeserializeOrder<MarketOnOpenOrder>(nullTimeJson);
TestOrderType(expected1);
TestOrderType(expected2);
TestOrderType(actual1);
TestOrderType(actual2);
}
[TestCase("Day")]
[TestCase("GoodTilCanceled")]
[TestCase("GoodTilDate")]
public void RoundTripUsingJsonConverter(string timeInForceStr)
{
TimeInForce timeInForce = null;
switch (timeInForceStr)
{
case "Day":
timeInForce = TimeInForce.Day;
break;
case "GoodTilCanceled":
timeInForce = TimeInForce.GoodTilCanceled;
break;
case "GoodTilDate":
timeInForce = TimeInForce.GoodTilDate(DateTime.UtcNow);
break;
}
var expected = new MarketOnOpenOrder(Symbol.Create("SPY", SecurityType.Equity, Market.USA), 1m, DateTime.UtcNow)
{
Id = 1,
ContingentId = 0,
BrokerId = new List<string> { "1" },
Price = 321.66m,
PriceCurrency = "USD",
LastFillTime = DateTime.UtcNow,
LastUpdateTime = DateTime.UtcNow,
CanceledTime = DateTime.UtcNow,
Status = OrderStatus.Filled,
OrderSubmissionData = new OrderSubmissionData(321.47m, 321.48m, 321.49m),
Properties = { TimeInForce = timeInForce },
PriceAdjustmentMode = DataNormalizationMode.Adjusted
};
var converter = new OrderJsonConverter();
var serialized = JsonConvert.SerializeObject(expected, converter);
var actual = JsonConvert.DeserializeObject<Order>(serialized, converter);
CollectionAssert.AreEqual(expected.BrokerId, actual.BrokerId);
Assert.AreEqual(expected.ContingentId, actual.ContingentId);
Assert.AreEqual(expected.Direction, actual.Direction);
Assert.AreEqual(expected.TimeInForce.GetType(), actual.TimeInForce.GetType());
Assert.AreEqual(expected.Id, actual.Id);
Assert.AreEqual(expected.Price, actual.Price);
Assert.AreEqual(expected.PriceCurrency, actual.PriceCurrency);
Assert.AreEqual(expected.SecurityType, actual.SecurityType);
Assert.AreEqual(expected.Status, actual.Status);
Assert.AreEqual(expected.Symbol, actual.Symbol);
Assert.AreEqual(expected.Tag, actual.Tag);
Assert.AreEqual(expected.Time, actual.Time);
Assert.AreEqual(expected.CreatedTime, actual.CreatedTime);
Assert.AreEqual(expected.LastFillTime, actual.LastFillTime);
Assert.AreEqual(expected.LastUpdateTime, actual.LastUpdateTime);
Assert.AreEqual(expected.CanceledTime, actual.CanceledTime);
Assert.AreEqual(expected.Type, actual.Type);
Assert.AreEqual(expected.Value, actual.Value);
Assert.AreEqual(expected.Quantity, actual.Quantity);
Assert.AreEqual(expected.TimeInForce.GetType(), actual.TimeInForce.GetType());
Assert.AreEqual(expected.Symbol.ID.Market, actual.Symbol.ID.Market);
Assert.AreEqual(expected.OrderSubmissionData.AskPrice, actual.OrderSubmissionData.AskPrice);
Assert.AreEqual(expected.OrderSubmissionData.BidPrice, actual.OrderSubmissionData.BidPrice);
Assert.AreEqual(expected.OrderSubmissionData.LastPrice, actual.OrderSubmissionData.LastPrice);
Assert.AreEqual(expected.PriceAdjustmentMode, actual.PriceAdjustmentMode);
}
[Test]
public void DeserializesOldSymbol()
{
const string json = @"{'Type':0,
'Value':99986.827413672,
'Id':1,
'ContingentId':0,
'BrokerId':[1],
'Symbol':{'Value':'SPY',
'Permtick':'SPY'},
'Price':100.086914328,
'Time':'2010-03-04T14:31:00Z',
'Quantity':999,
'Status':3,
'TimeInForce':0,
'Tag':'',
'SecurityType':1,
'Direction':0,
'AbsoluteQuantity':999}";
var order = DeserializeOrder<MarketOrder>(json);
var actual = order.Symbol;
Assert.AreEqual(Symbols.SPY, actual);
Assert.AreEqual(Market.USA, actual.ID.Market);
}
[Test]
public void WorksWithJsonConvert()
{
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = {new OrderJsonConverter()}
};
const string json = @"{'Type':0,
'Value':99986.827413672,
'Id':1,
'ContingentId':0,
'BrokerId':[1],
'Symbol':{'Value':'SPY',
'Permtick':'SPY'},
'Price':100.086914328,
'Time':'2010-03-04T14:31:00Z',
'Quantity':999,
'Status':3,
'TimeInForce':1,
'Tag':'',
'SecurityType':1,
'Direction':0,
'AbsoluteQuantity':999}";
var order = JsonConvert.DeserializeObject<Order>(json);
Assert.IsInstanceOf<MarketOrder>(order);
Assert.AreEqual(Market.USA, order.Symbol.ID.Market);
Assert.IsTrue(order.TimeInForce is DayTimeInForce);
}
[Test]
public void DeserializesOldDurationProperty()
{
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = { new OrderJsonConverter() }
};
// The Duration property has been renamed to TimeInForce,
// we still want to deserialize old JSON files containing Duration.
const string json = @"{'Type':0,
'Value':99986.827413672,
'Id':1,
'ContingentId':0,
'BrokerId':[1],
'Symbol':{'Value':'SPY',
'Permtick':'SPY'},
'Price':100.086914328,
'Time':'2010-03-04T14:31:00Z',
'Quantity':999,
'Status':3,
'Duration':1,
'Tag':'',
'SecurityType':1,
'Direction':0,
'AbsoluteQuantity':999}";
var order = JsonConvert.DeserializeObject<Order>(json);
Assert.IsInstanceOf<MarketOrder>(order);
Assert.AreEqual(Market.USA, order.Symbol.ID.Market);
Assert.IsTrue(order.TimeInForce is DayTimeInForce);
}
[Test]
public void DeserializesOldDurationValueProperty()
{
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = { new OrderJsonConverter() }
};
// The DurationValue property has been moved to GoodTilDateTimeInforce.Expiry,
// we still want to deserialize old JSON files containing Duration.
const string json = @"{'Type':0,
'Value':99986.827413672,
'Id':1,
'ContingentId':0,
'BrokerId':[1],
'Symbol':{'Value':'SPY',
'Permtick':'SPY'},
'Price':100.086914328,
'Time':'2010-03-04T14:31:00Z',
'Quantity':999,
'Status':3,
'Duration':2,
'DurationValue':'2010-04-04T14:31:00Z',
'Tag':'',
'SecurityType':1,
'Direction':0,
'AbsoluteQuantity':999}";
var order = JsonConvert.DeserializeObject<Order>(json);
Assert.IsInstanceOf<MarketOrder>(order);
Assert.AreEqual(Market.USA, order.Symbol.ID.Market);
Assert.IsTrue(order.TimeInForce is GoodTilDateTimeInForce);
var timeInForce = (GoodTilDateTimeInForce)order.TimeInForce;
Assert.AreEqual(new DateTime(2010, 4, 4, 14, 31, 0), timeInForce.Expiry);
}
[Test]
public void DeserializesDecimalizedQuantity()
{
var expected = new MarketOrder(Symbols.BTCUSD, 0.123m, DateTime.Today);
TestOrderType(expected);
}
[Test]
public void DeserializesOrderGoodTilCanceledTimeInForce()
{
var orderProperties = new OrderProperties { TimeInForce = TimeInForce.GoodTilCanceled };
var expected = new MarketOrder(Symbols.BTCUSD, 0.123m, DateTime.Today, "", orderProperties);
TestOrderType(expected);
}
[Test]
public void DeserializesOrderDayTimeInForce()
{
var orderProperties = new OrderProperties { TimeInForce = TimeInForce.Day };
var expected = new MarketOrder(Symbols.BTCUSD, 0.123m, DateTime.Today, "", orderProperties);
TestOrderType(expected);
}
[Test]
public void DeserializesOrderGoodTilDateTimeInForce()
{
var expiry = new DateTime(2018, 5, 26);
var orderProperties = new OrderProperties { TimeInForce = TimeInForce.GoodTilDate(expiry) };
var expected = new MarketOrder(Symbols.BTCUSD, 0.123m, DateTime.Today, "", orderProperties);
TestOrderType(expected);
var json = JsonConvert.SerializeObject(expected);
var actual = DeserializeOrder<MarketOrder>(json);
var gtd = (GoodTilDateTimeInForce)actual.Properties.TimeInForce;
Assert.AreEqual(expiry, gtd.Expiry);
}
[Test]
public void JsonIgnores()
{
var json = JsonConvert.SerializeObject(new MarketOrder(Symbols.BTCUSD, 0.123m, DateTime.Today));
Assert.IsFalse(json.Contains("Tag"));
Assert.IsFalse(json.Contains("AbsoluteQuantity"));
json = JsonConvert.SerializeObject(new MarketOrder(Symbols.BTCUSD, 0.123m, DateTime.Today, "This is a Tag"));
Assert.IsTrue(json.Contains("Tag"));
Assert.IsTrue(json.Contains("This is a Tag"));
}
[Test]
public void TimeInForceInProperties()
{
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = { new OrderJsonConverter() }
};
const string json = @"{'Type':0,
'Value':99986.827413672,
'Id':1,
'ContingentId':0,
'BrokerId':[1],
'Symbol':{'Value':'SPY',
'Permtick':'SPY'},
'Price':100.086914328,
'Time':'2010-03-04T14:31:00Z',
'Quantity':999,
'Status':3,
'Properties': {
'TimeInForce': 1
},
'Tag':'',
'SecurityType':1,
'Direction':0,
'AbsoluteQuantity':999}";
var order = JsonConvert.DeserializeObject<Order>(json);
Assert.IsInstanceOf<MarketOrder>(order);
Assert.AreEqual(Market.USA, order.Symbol.ID.Market);
Assert.IsTrue(order.TimeInForce is DayTimeInForce);
}
private static T TestOrderType<T>(T expected)
where T : Order
{
var json = JsonConvert.SerializeObject(expected);
var actual = DeserializeOrder<T>(json);
Assert.IsInstanceOf<T>(actual);
Assert.AreEqual(expected.AbsoluteQuantity, actual.AbsoluteQuantity);
CollectionAssert.AreEqual(expected.BrokerId, actual.BrokerId);
Assert.AreEqual(expected.ContingentId, actual.ContingentId);
Assert.AreEqual(expected.Direction, actual.Direction);
Assert.AreEqual(expected.TimeInForce.GetType(), actual.TimeInForce.GetType());
Assert.AreEqual(expected.Id, actual.Id);
Assert.AreEqual(expected.Price, actual.Price);
Assert.AreEqual(expected.SecurityType, actual.SecurityType);
Assert.AreEqual(expected.Status, actual.Status);
Assert.AreEqual(expected.Symbol, actual.Symbol);
Assert.AreEqual(expected.Tag, actual.Tag);
Assert.AreEqual(expected.Time, actual.Time);
Assert.AreEqual(expected.LastFillTime, actual.LastFillTime);
Assert.AreEqual(expected.LastUpdateTime, actual.LastUpdateTime);
Assert.AreEqual(expected.Type, actual.Type);
Assert.AreEqual(expected.Value, actual.Value);
Assert.AreEqual(expected.Quantity, actual.Quantity);
Assert.AreEqual(expected.Symbol.ID.Market, actual.Symbol.ID.Market);
TestGroupOrderManager(expected.GroupOrderManager, actual.GroupOrderManager);
return (T) actual;
}
private static void TestGroupOrderManager(GroupOrderManager expected, GroupOrderManager actual)
{
if (expected == null)
{
Assert.IsNull(actual);
return;
}
Assert.IsNotNull(actual);
Assert.AreEqual(expected.Id, actual.Id);
Assert.AreEqual(expected.Quantity, actual.Quantity);
Assert.AreEqual(expected.Count, actual.Count);
Assert.AreEqual(expected.LimitPrice, actual.LimitPrice);
Assert.AreEqual(expected.Direction, actual.Direction);
CollectionAssert.AreEqual(expected.OrderIds, actual.OrderIds);
}
private static Order DeserializeOrder<T>(string json) where T : Order
{
var converter = new OrderJsonConverter();
using var reader = new JsonTextReader(new StringReader(json));
var jsonSerializer = new JsonSerializer();
jsonSerializer.Converters.Add(converter);
var actual = jsonSerializer.Deserialize<Order>(reader);
return actual;
}
}
}