diff --git a/Algorithm.CSharp/DelayedSettlementAfterManualSecurityRemovalAlgorithm.cs b/Algorithm.CSharp/DelayedSettlementAfterManualSecurityRemovalAlgorithm.cs
new file mode 100644
index 000000000000..1c59e0914a48
--- /dev/null
+++ b/Algorithm.CSharp/DelayedSettlementAfterManualSecurityRemovalAlgorithm.cs
@@ -0,0 +1,146 @@
+/*
+ * 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.Collections.Generic;
+using QuantConnect.Interfaces;
+using System.Linq;
+using System;
+using QuantConnect.Securities;
+using QuantConnect.Securities.Option;
+
+namespace QuantConnect.Algorithm.CSharp
+{
+ ///
+ /// Algorithm asserting that delayed cash settlement is applied even when the option contract is manually removed
+ ///
+ public class DelayedSettlementAfterManualSecurityRemovalAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
+ {
+ private Symbol _optionSymbol;
+
+ public override void Initialize()
+ {
+ SetStartDate(2015, 12, 24);
+ SetEndDate(2015, 12, 31);
+ SetCash(100000);
+
+ var equity = AddEquity("GOOG");
+
+ _optionSymbol = OptionChainProvider.GetOptionContractList(equity.Symbol, Time)
+ .OrderByDescending(symbol => symbol.ID.Date)
+ .First(optionContract => optionContract.ID.OptionRight == OptionRight.Call);
+ var option = AddOptionContract(_optionSymbol);
+
+ option.SetSettlementModel(new DelayedSettlementModel(Option.DefaultSettlementDays, Option.DefaultSettlementTime));
+
+ Schedule.On(DateRules.On(StartDate), TimeRules.BeforeMarketClose(_optionSymbol, 30), () =>
+ {
+ MarketOrder(_optionSymbol, 1);
+ });
+
+ Schedule.On(DateRules.On(StartDate), TimeRules.BeforeMarketClose(_optionSymbol, 1), () =>
+ {
+ RemoveOptionContract(_optionSymbol);
+ });
+
+ var expectedSettlementDate = new DateTime(2015, 12, 28);
+
+ Schedule.On(DateRules.On(expectedSettlementDate), TimeRules.AfterMarketOpen(_optionSymbol), () =>
+ {
+ if (Portfolio.UnsettledCash == 0)
+ {
+ throw new Exception($"Expected unsettled cash to be non-zero at {Time}");
+ }
+ });
+
+ Schedule.On(DateRules.On(expectedSettlementDate), TimeRules.BeforeMarketClose(_optionSymbol), () =>
+ {
+ if (Portfolio.UnsettledCash != 0)
+ {
+ throw new Exception($"Expected unsettled cash to be zero at {Time}");
+ }
+ });
+ }
+
+ public override void OnEndOfAlgorithm()
+ {
+ if (Transactions.OrdersCount != 2)
+ {
+ throw new Exception($"Expected 2 orders, found {Transactions.OrdersCount}");
+ }
+
+ if (Portfolio.Invested)
+ {
+ throw new Exception("Expected no holdings at end of algorithm");
+ }
+
+ if (Portfolio.UnsettledCash != 0)
+ {
+ throw new Exception($"Expected no unsettled cash at end of algorithm, found {Portfolio.UnsettledCash}");
+ }
+ }
+
+ ///
+ /// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
+ ///
+ public bool CanRunLocally { get; } = true;
+
+ ///
+ /// This is used by the regression test system to indicate which languages this algorithm is written in.
+ ///
+ public Language[] Languages { get; } = { Language.CSharp };
+
+ ///
+ /// Data Points count of all timeslices of algorithm
+ ///
+ public long DataPoints => 7122;
+
+ ///
+ /// Data Points count of the algorithm history
+ ///
+ public int AlgorithmHistoryDataPoints => 0;
+
+ ///
+ /// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
+ ///
+ public Dictionary ExpectedStatistics => new Dictionary
+ {
+ {"Total Trades", "2"},
+ {"Average Win", "0%"},
+ {"Average Loss", "-0.36%"},
+ {"Compounding Annual Return", "-15.857%"},
+ {"Drawdown", "0.400%"},
+ {"Expectancy", "-1"},
+ {"Net Profit", "-0.362%"},
+ {"Sharpe Ratio", "0"},
+ {"Sortino Ratio", "0"},
+ {"Probabilistic Sharpe Ratio", "0%"},
+ {"Loss Rate", "100%"},
+ {"Win Rate", "0%"},
+ {"Profit-Loss Ratio", "0"},
+ {"Alpha", "0"},
+ {"Beta", "0"},
+ {"Annual Standard Deviation", "0"},
+ {"Annual Variance", "0"},
+ {"Information Ratio", "2.537"},
+ {"Tracking Error", "0.104"},
+ {"Treynor Ratio", "0"},
+ {"Total Fees", "$2.00"},
+ {"Estimated Strategy Capacity", "$150000.00"},
+ {"Lowest Capacity Asset", "GOOCV WRCOZDXBITL2|GOOCV VP83T1ZUHROL"},
+ {"Portfolio Turnover", "1.06%"},
+ {"OrderListHash", "490dd9430dec6cb3daadcca495ff5f12"}
+ };
+ }
+}
diff --git a/Algorithm.CSharp/SetCustomSettlementModelRegressionAlgorithm.cs b/Algorithm.CSharp/SetCustomSettlementModelRegressionAlgorithm.cs
index 31302cb63859..c572b778c9f1 100644
--- a/Algorithm.CSharp/SetCustomSettlementModelRegressionAlgorithm.cs
+++ b/Algorithm.CSharp/SetCustomSettlementModelRegressionAlgorithm.cs
@@ -15,7 +15,6 @@
using QuantConnect.Data;
using QuantConnect.Securities;
-using QuantConnect.Brokerages;
using System;
using QuantConnect.Interfaces;
using System.Collections.Generic;
@@ -133,5 +132,13 @@ public void Scan(ScanSettlementModelParameters settlementParameters)
settlementParameters.Portfolio.CashBook[_currency].AddAmount(-_amount);
}
}
+
+ ///
+ /// Gets the unsettled cash amount for the security
+ ///
+ public CashAmount GetUnsettledCash()
+ {
+ return default;
+ }
}
}
diff --git a/Algorithm.Python/CustomSettlementModelRegressionAlgorithm.py b/Algorithm.Python/CustomSettlementModelRegressionAlgorithm.py
index e9a417af3e0b..23d31b4e0d75 100644
--- a/Algorithm.Python/CustomSettlementModelRegressionAlgorithm.py
+++ b/Algorithm.Python/CustomSettlementModelRegressionAlgorithm.py
@@ -51,6 +51,9 @@ def Scan(self, parameters):
if parameters.UtcTime == datetime(2013, 10, 6):
parameters.Portfolio.CashBook[self.currency].AddAmount(-self.amount)
+ def GetUnsettledCash(self):
+ return None
+
class CustomBrokerageModelWithCustomSettlementModel(CustomBrokerageModel):
def GetSettlementModel(self, security):
return CustomSettlementModel()
diff --git a/Common/Python/SettlementModelPythonWrapper.cs b/Common/Python/SettlementModelPythonWrapper.cs
index 2bb368e02a37..aac75b3a9c1c 100644
--- a/Common/Python/SettlementModelPythonWrapper.cs
+++ b/Common/Python/SettlementModelPythonWrapper.cs
@@ -31,7 +31,7 @@ public class SettlementModelPythonWrapper : ISettlementModel
/// Settlement Python Model
public SettlementModelPythonWrapper(PyObject model)
{
- _model = model;
+ _model = model.ValidateImplementationOf();
}
///
@@ -57,5 +57,22 @@ public void Scan(ScanSettlementModelParameters settlementParameters)
_model.Scan(settlementParameters);
}
}
+
+ ///
+ /// Gets the unsettled cash amount for the security
+ ///
+ public CashAmount GetUnsettledCash()
+ {
+ using (Py.GIL())
+ {
+ var result = _model.GetUnsettledCash();
+ if (result == null)
+ {
+ return default;
+ }
+
+ return result;
+ }
+ }
}
}
diff --git a/Common/Securities/AccountCurrencyImmediateSettlementModel.cs b/Common/Securities/AccountCurrencyImmediateSettlementModel.cs
index abe1f00942a0..3681d432ccc9 100644
--- a/Common/Securities/AccountCurrencyImmediateSettlementModel.cs
+++ b/Common/Securities/AccountCurrencyImmediateSettlementModel.cs
@@ -19,13 +19,13 @@ namespace QuantConnect.Securities
/// Represents the model responsible for applying cash settlement rules
///
/// This model converts the amount to the account currency and applies cash settlement immediately
- public class AccountCurrencyImmediateSettlementModel : ISettlementModel
+ public class AccountCurrencyImmediateSettlementModel : ImmediateSettlementModel
{
///
/// Applies cash settlement rules
///
/// The funds application parameters
- public void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsParameters)
+ public override void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsParameters)
{
var currency = applyFundsParameters.CashAmount.Currency;
var amount = applyFundsParameters.CashAmount.Amount;
@@ -34,13 +34,5 @@ public void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsParameters)
portfolio.CashBook[portfolio.CashBook.AccountCurrency].AddAmount(amountInAccountCurrency);
}
-
- ///
- /// Scan for pending settlements
- ///
- /// The settlement parameters
- public void Scan(ScanSettlementModelParameters settlementParameters)
- {
- }
}
}
diff --git a/Common/Securities/CashAmount.cs b/Common/Securities/CashAmount.cs
index 8920a55176cb..7a2673dcc5ea 100644
--- a/Common/Securities/CashAmount.cs
+++ b/Common/Securities/CashAmount.cs
@@ -1,4 +1,4 @@
-/*
+/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
diff --git a/Common/Securities/DelayedSettlementModel.cs b/Common/Securities/DelayedSettlementModel.cs
index 332071ff5809..49ccb78bb72f 100644
--- a/Common/Securities/DelayedSettlementModel.cs
+++ b/Common/Securities/DelayedSettlementModel.cs
@@ -1,11 +1,11 @@
/*
* 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");
+ *
+ * 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.
@@ -15,6 +15,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
namespace QuantConnect.Securities
{
@@ -26,6 +27,7 @@ public class DelayedSettlementModel : ISettlementModel
{
private readonly int _numberOfDays;
private readonly TimeSpan _timeOfDay;
+ private CashBook _cashBook;
///
/// The list of pending funds waiting for settlement time
@@ -85,6 +87,12 @@ public void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsParameters)
portfolio.CashBook[currency].AddAmount(amount);
}
+
+ // We just keep it to use currency conversion in GetUnsettledCash method
+ if (_cashBook == null)
+ {
+ _cashBook = portfolio.UnsettledCashBook;
+ }
}
///
@@ -110,5 +118,24 @@ public void Scan(ScanSettlementModelParameters settlementParameters)
}
}
}
+
+ ///
+ /// Gets the unsettled cash amount for the security
+ ///
+ public CashAmount GetUnsettledCash()
+ {
+ var accountCurrency = _cashBook != null ? _cashBook.AccountCurrency : Currencies.USD;
+
+ lock (_unsettledCashAmounts)
+ {
+ if (_unsettledCashAmounts.Count == 0)
+ {
+ return default;
+ }
+
+ return new CashAmount(_unsettledCashAmounts.Sum(x => _cashBook.ConvertToAccountCurrency(x.Amount, x.Currency)), accountCurrency);
+ }
+
+ }
}
}
diff --git a/Common/Securities/ISettlementModel.cs b/Common/Securities/ISettlementModel.cs
index 22b0b67a1652..04b6bc8e75c5 100644
--- a/Common/Securities/ISettlementModel.cs
+++ b/Common/Securities/ISettlementModel.cs
@@ -1,11 +1,11 @@
/*
* 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");
+ *
+ * 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.
@@ -31,5 +31,10 @@ public interface ISettlementModel
///
/// The settlement parameters
void Scan(ScanSettlementModelParameters settlementParameters);
+
+ ///
+ /// Gets the unsettled cash amount for the security
+ ///
+ CashAmount GetUnsettledCash();
}
}
diff --git a/Common/Securities/ImmediateSettlementModel.cs b/Common/Securities/ImmediateSettlementModel.cs
index 6b727043e6d7..5becda904e9d 100644
--- a/Common/Securities/ImmediateSettlementModel.cs
+++ b/Common/Securities/ImmediateSettlementModel.cs
@@ -1,11 +1,11 @@
/*
* 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");
+ *
+ * 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.
@@ -39,5 +39,13 @@ public virtual void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsPar
public virtual void Scan(ScanSettlementModelParameters settlementParameters)
{
}
+
+ ///
+ /// Gets the unsettled cash amount for the security
+ ///
+ public virtual CashAmount GetUnsettledCash()
+ {
+ return default;
+ }
}
}
diff --git a/Engine/DataFeeds/PendingRemovalsManager.cs b/Engine/DataFeeds/PendingRemovalsManager.cs
index 13c9a7d1b9dd..dfdb37406cd8 100644
--- a/Engine/DataFeeds/PendingRemovalsManager.cs
+++ b/Engine/DataFeeds/PendingRemovalsManager.cs
@@ -1,4 +1,4 @@
-/*
+/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -61,6 +61,14 @@ private bool IsSafeToRemove(Security member, Universe universe)
// covers the options use case
return false;
}
+
+ // don't remove if there are unsettled positions
+ var unsettledCash = member.SettlementModel.GetUnsettledCash();
+ if (unsettledCash != default && unsettledCash.Amount > 0)
+ {
+ return false;
+ }
+
return true;
}
diff --git a/Tests/Common/Brokerages/BrokerageModelTests.cs b/Tests/Common/Brokerages/BrokerageModelTests.cs
index a61bebd0aaf7..7231cb15a7a4 100644
--- a/Tests/Common/Brokerages/BrokerageModelTests.cs
+++ b/Tests/Common/Brokerages/BrokerageModelTests.cs
@@ -410,6 +410,9 @@ raise ValueError(""Pepe"")
def Scan(self, parameters):
raise ValueError(""Pepe2"")
+ def GetUnsettledCash(self):
+ raise ValueError(""Pepe3"")
+
class CustomBrokerageModel(DefaultBrokerageModel):
def GetSettlementModel(self, securities):
return CustomSettlementModel()
@@ -429,6 +432,9 @@ def GetSettlementModel(self, securities):
ex = Assert.Throws(() => ((dynamic)settlementModel).Scan(scanParameters));
Assert.AreEqual("ValueError", ex.Type.Name);
Assert.AreEqual("Pepe2", ex.Message);
+ ex = Assert.Throws(() => ((dynamic)settlementModel).GetUnsettledCash());
+ Assert.AreEqual("ValueError", ex.Type.Name);
+ Assert.AreEqual("Pepe3", ex.Message);
}
}
diff --git a/Tests/Engine/DataFeeds/PendingRemovalsManagerTests.cs b/Tests/Engine/DataFeeds/PendingRemovalsManagerTests.cs
index b216ca4b5ff1..51becf08fc83 100644
--- a/Tests/Engine/DataFeeds/PendingRemovalsManagerTests.cs
+++ b/Tests/Engine/DataFeeds/PendingRemovalsManagerTests.cs
@@ -1,4 +1,4 @@
-/*
+/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -30,13 +30,16 @@ namespace QuantConnect.Tests.Engine.DataFeeds
[TestFixture]
public class PendingRemovalsManagerTests
{
+ private static readonly DateTime Noon = new DateTime(2015, 11, 2, 12, 0, 0);
+ private static readonly TimeKeeper TimeKeeper = new TimeKeeper(Noon.ConvertToUtc(TimeZones.NewYork), new[] { TimeZones.NewYork });
+
[Test]
public void ReturnedRemoved_Add()
{
var orderProvider = new FakeOrderProcessor();
var pendingRemovals = new PendingRemovalsManager(orderProvider);
var security = SecurityTests.GetSecurity();
- var universe = new TestUniverse();
+ using var universe = new TestUniverse();
var result = pendingRemovals.TryRemoveMember(security, universe);
@@ -54,7 +57,7 @@ public void ReturnedRemoved_Check()
var orderProvider = new FakeOrderProcessor();
var pendingRemovals = new PendingRemovalsManager(orderProvider);
var security = SecurityTests.GetSecurity();
- var universe = new TestUniverse();
+ using var universe = new TestUniverse();
orderProvider.AddOrder(new LimitOrder(security.Symbol, 1, 1, DateTime.UtcNow));
pendingRemovals.TryRemoveMember(security, universe);
orderProvider.Clear();
@@ -79,7 +82,7 @@ public void WontRemoveBecauseOfUnderlying()
// we add an order of the equity option
orderProvider.AddOrder(new LimitOrder(equityOption.Symbol, 1, 1, DateTime.UtcNow));
- var universe = new TestUniverse();
+ using var universe = new TestUniverse();
universe.AddMember(DateTime.UtcNow, equity, false);
universe.AddMember(DateTime.UtcNow, equityOption, false);
@@ -97,7 +100,7 @@ public void WontRemoveBecauseOpenOrder_Add()
var orderProvider = new FakeOrderProcessor();
var pendingRemovals = new PendingRemovalsManager(orderProvider);
var security = SecurityTests.GetSecurity();
- var universe = new TestUniverse();
+ using var universe = new TestUniverse();
orderProvider.AddOrder(new LimitOrder(security.Symbol, 1, 1, DateTime.UtcNow));
Assert.IsNull(pendingRemovals.TryRemoveMember(security, universe));
@@ -113,7 +116,7 @@ public void WontRemoveBecauseOpenOrder_Check()
var orderProvider = new FakeOrderProcessor();
var pendingRemovals = new PendingRemovalsManager(orderProvider);
var security = SecurityTests.GetSecurity();
- var universe = new TestUniverse();
+ using var universe = new TestUniverse();
orderProvider.AddOrder(new LimitOrder(security.Symbol, 1, 1, DateTime.UtcNow));
Assert.IsNull(pendingRemovals.TryRemoveMember(security, universe));
@@ -130,7 +133,7 @@ public void WontRemoveBecauseHoldings_Add()
var orderProvider = new FakeOrderProcessor();
var pendingRemovals = new PendingRemovalsManager(orderProvider);
var security = SecurityTests.GetSecurity();
- var universe = new TestUniverse();
+ using var universe = new TestUniverse();
security.Holdings.SetHoldings(10, 10);
Assert.IsNull(pendingRemovals.TryRemoveMember(security, universe));
@@ -146,7 +149,7 @@ public void WontRemoveBecauseHoldings_Check()
var orderProvider = new FakeOrderProcessor();
var pendingRemovals = new PendingRemovalsManager(orderProvider);
var security = SecurityTests.GetSecurity();
- var universe = new TestUniverse();
+ using var universe = new TestUniverse();
security.Holdings.SetHoldings(10, 10);
Assert.IsNull(pendingRemovals.TryRemoveMember(security, universe));
@@ -163,7 +166,7 @@ public void WontRemoveBecauseTarget_Add()
var orderProvider = new FakeOrderProcessor();
var pendingRemovals = new PendingRemovalsManager(orderProvider);
var security = SecurityTests.GetSecurity();
- var universe = new TestUniverse();
+ using var universe = new TestUniverse();
security.Holdings.Target = new PortfolioTarget(security.Symbol, 10);
Assert.IsNull(pendingRemovals.TryRemoveMember(security, universe));
@@ -179,7 +182,7 @@ public void WontRemoveBecauseTarget_Check()
var orderProvider = new FakeOrderProcessor();
var pendingRemovals = new PendingRemovalsManager(orderProvider);
var security = SecurityTests.GetSecurity();
- var universe = new TestUniverse();
+ using var universe = new TestUniverse();
security.Holdings.Target = new PortfolioTarget(security.Symbol, 10);
Assert.IsNull(pendingRemovals.TryRemoveMember(security, universe));
@@ -196,7 +199,7 @@ public void WontBeReturnedBecauseReSelected()
var orderProvider = new FakeOrderProcessor();
var pendingRemovals = new PendingRemovalsManager(orderProvider);
var security = SecurityTests.GetSecurity();
- var universe = new TestUniverse();
+ using var universe = new TestUniverse();
orderProvider.AddOrder(new LimitOrder(security.Symbol, 1, 1, DateTime.UtcNow));
pendingRemovals.TryRemoveMember(security, universe);
@@ -208,6 +211,29 @@ public void WontBeReturnedBecauseReSelected()
Assert.AreEqual(0, pendingRemovals.PendingRemovals.Values.Count());
}
+ [Test]
+ public void WontRemoveBecauseUnsettledFunds()
+ {
+ var orderProvider = new FakeOrderProcessor();
+ var pendingRemovals = new PendingRemovalsManager(orderProvider);
+ using var universe = new TestUniverse();
+ var security = SecurityTests.GetSecurity();
+
+ security.SetSettlementModel(new DelayedSettlementModel(1, TimeSpan.FromHours(8)));
+ var securities = new SecurityManager(TimeKeeper);
+ var transactions = new SecurityTransactionManager(null, securities);
+ var portfolio = new SecurityPortfolioManager(securities, transactions, new AlgorithmSettings());
+ security.SettlementModel.ApplyFunds(new ApplyFundsSettlementModelParameters(portfolio, security, TimeKeeper.UtcTime.Date.AddDays(1),
+ new CashAmount(1000, Currencies.USD), null));
+
+ Assert.IsNull(pendingRemovals.TryRemoveMember(security, universe));
+ Assert.IsFalse(pendingRemovals.CheckPendingRemovals(new HashSet(), universe).Any());
+ Assert.AreEqual(1, pendingRemovals.PendingRemovals.Keys.Count());
+ Assert.AreEqual(1, pendingRemovals.PendingRemovals.Values.Count());
+ Assert.AreEqual(universe, pendingRemovals.PendingRemovals.Keys.First());
+ Assert.AreEqual(security, pendingRemovals.PendingRemovals.Values.First().First());
+ }
+
private class TestUniverse : Universe
{
public TestUniverse()
diff --git a/Tests/Python/SettlementModelPythonWrapperTests.cs b/Tests/Python/SettlementModelPythonWrapperTests.cs
new file mode 100644
index 000000000000..8198a77735e2
--- /dev/null
+++ b/Tests/Python/SettlementModelPythonWrapperTests.cs
@@ -0,0 +1,59 @@
+/*
+ * 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 NUnit.Framework;
+using Python.Runtime;
+using QuantConnect.AlgorithmFactory.Python.Wrappers;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using QuantConnect.Orders;
+using Moq;
+using static QuantConnect.Tests.Engine.PerformanceBenchmarkAlgorithms;
+using QuantConnect.Python;
+using QuantConnect.Securities;
+
+namespace QuantConnect.Tests.Python
+{
+ [TestFixture]
+ public class SettlementModelPythonWrapperTests
+ {
+ [Test]
+ public void GetsDefaultUnsettledCashFromNone()
+ {
+ using (Py.GIL())
+ {
+ var testModule = PyModule.FromString("testModule",
+ @"
+class CustomSettlementModel:
+ def ApplyFunds(self, parameters):
+ pass
+
+ def Scan(self, parameters):
+ pass
+
+ def GetUnsettledCash(self):
+ return None
+ ");
+
+ var settlementModel = new SettlementModelPythonWrapper(testModule.GetAttr("CustomSettlementModel").Invoke());
+ var result = settlementModel.GetUnsettledCash();
+ Assert.AreEqual(default(CashAmount), result);
+
+ }
+ }
+ }
+}