/*
* 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 NodaTime;
using NUnit.Framework;
using QuantConnect.Data.Market;
using QuantConnect.Securities;
namespace QuantConnect.Tests.Common.Securities
{
[TestFixture]
public class BuyingPowerModelTests
{
private BuyingPowerModel _model;
[OneTimeSetUp]
public void Setup()
{
_model = new BuyingPowerModel();
}
// Current Order Margin
[TestCase(-40, 25, -900, 1, 4)] // -1000
[TestCase(-36, 25, -880, 1, 1)] // -900
[TestCase(-35, 25, -900, 1, -1)] // -875
[TestCase(-34, 25, -880, 1, -1)] // -850
[TestCase(48, 25, 1050, 1, -6)] // 1200
[TestCase(49, 25, 1212, 1, -1)] // 1225
[TestCase(44, 25, 1200, 1, 4)] // 1100
[TestCase(45, 25, 1250, 1, 5)] // 1125
[TestCase(80, 25, -1250, 1, -130)] // 2000
[TestCase(45.5, 25, 1240, 0.5, 4)] // 1125
[TestCase(45.75, 25, 1285, 0.25, 5.5)] // 1125
[TestCase(-40, 25, 1500, 1, 100)] // -1000
[TestCase(-40.5, 12.5, 1505, .5, 160.5)]// -506.25
[TestCase(-40.5, 12.5, 1508, .5, 161)] // -506.25
public void OrderCalculation(decimal currentHoldings, decimal perUnitMargin, decimal targetMargin, decimal lotSize, decimal expectedOrderSize)
{
var spy = SetupSecurity(currentHoldings, lotSize, perUnitMargin);
var currentHoldingsMargin = _model.GetInitialMarginRequirement(spy, spy.Holdings.Quantity);
// Determine the order size to get us to our target margin
var orderSize = _model.GetAmountToOrder(spy, targetMargin, perUnitMargin, out _);
Assert.AreEqual(expectedOrderSize, orderSize);
// Determine the final margin and assert we have met our target condition
var resultMargin = currentHoldingsMargin + (orderSize * perUnitMargin);
Assert.IsTrue(Math.Abs(resultMargin) <= Math.Abs(targetMargin));
}
// Current Order Margin
[TestCase(-40, 25, -900, 1, -36)] // -1000
[TestCase(-36, 25, -880, 1, -35)] // -900
[TestCase(-35, 25, -900, 1, -36)] // -875
[TestCase(-34, 25, -880, 1, -35)] // -850
[TestCase(48, 25, 1050, 1, 42)] // 1200
[TestCase(49, 25, 1212, 1, 48)] // 1225
[TestCase(44, 25, 1200, 1, 48)] // 1100
[TestCase(45, 25, 1250, 1, 50)] // 1125
[TestCase(80, 25, -1250, 1, -50)] // 2000
[TestCase(45.5, 25, 1240, 0.5, 49.5)] // 1125
[TestCase(45.75, 25, 1285, 0.25, 51.25)]// 1125
[TestCase(-40, 25, 1500, 1, 60)] // -1000
[TestCase(-40.5, 12.5, 1505, .5, 120)] // -506.25
[TestCase(-40.5, 12.5, 1508, .5, 120.5)]// -506.25
public void OrderAdjustmentCalculation(decimal currentOrderSize, decimal perUnitMargin, decimal targetMargin, decimal lotSize, decimal expectedOrderSize)
{
var spy = SetupSecurity(currentOrderSize, lotSize, perUnitMargin);
var currentHoldingsMargin = _model.GetInitialMarginRequirement(spy, spy.Holdings.Quantity);
// Determine the adjustment to get us to our target margin and apply it
// Use our GetAmountToOrder for determining adjustment to reach the end goal
var orderAdjustment =
_model.GetAmountToOrder(spy, targetMargin, perUnitMargin, out _);
// Apply the change in margin
var resultMargin = currentHoldingsMargin + (orderAdjustment * perUnitMargin);
// Assert after our adjustment we have met our target condition
Assert.IsTrue(Math.Abs(resultMargin) <= Math.Abs(targetMargin));
// Verify our adjustment meets our expected order size
var adjustOrderSize = currentOrderSize + orderAdjustment;
Assert.AreEqual(expectedOrderSize, adjustOrderSize);
}
///
/// Helper method for tests, sets up an equity security with our properties
///
/// Equity with the given setup values
private static Security SetupSecurity(decimal currentHoldings, decimal lotSize, decimal perUnitMargin)
{
var spy = new QuantConnect.Securities.Equity.Equity(Symbols.SPY, SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc), new Cash("$", 0, 1),
new SymbolProperties(null, "$", 1, 0.01m, lotSize, null, 0), null, null, new SecurityCache());
spy.Holdings.SetHoldings(perUnitMargin, currentHoldings);
spy.SetLeverage(1);
spy.SetMarketPrice(new TradeBar
{
Time = DateTime.Now,
Symbol = spy.Symbol,
Open = perUnitMargin,
High = perUnitMargin,
Low = perUnitMargin,
Close = perUnitMargin
});
return spy;
}
}
}