From 6ca89d82985df951e6a6ff997d04c9162f4f106e Mon Sep 17 00:00:00 2001 From: Marinovsky Date: Tue, 9 Jan 2024 10:11:05 -0500 Subject: [PATCH] Rebase - Add Support --- ...ustomSettlementModelRegressionAlgorithm.cs | 137 ++++++++++++++++++ ...ustomSettlementModelRegressionAlgorithm.py | 16 +- ...ustomSettlementModelRegressionAlgorithm.py | 10 ++ Common/Securities/Security.cs | 18 +++ 4 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 Algorithm.CSharp/SetCustomSettlementModelRegressionAlgorithm.cs create mode 100644 Algorithm.Python/SetCustomSettlementModelRegressionAlgorithm.py diff --git a/Algorithm.CSharp/SetCustomSettlementModelRegressionAlgorithm.cs b/Algorithm.CSharp/SetCustomSettlementModelRegressionAlgorithm.cs new file mode 100644 index 000000000000..31302cb63859 --- /dev/null +++ b/Algorithm.CSharp/SetCustomSettlementModelRegressionAlgorithm.cs @@ -0,0 +1,137 @@ +/* + * 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 QuantConnect.Data; +using QuantConnect.Securities; +using QuantConnect.Brokerages; +using System; +using QuantConnect.Interfaces; +using System.Collections.Generic; + +namespace QuantConnect.Algorithm.CSharp +{ + /// + /// Regression algorithm to test we can specify a custom settlement model using Security.SetSettlementModel() method + /// + public class SetCustomSettlementModelRegressionAlgorithm: QCAlgorithm, IRegressionAlgorithmDefinition + { + private Security _spy; + public override void Initialize() + { + SetStartDate(2013, 10, 7); + SetEndDate(2013, 10, 11); + SetCash(10000); + _spy = AddEquity("SPY", Resolution.Daily); + _spy.SetSettlementModel(new CustomSettlementModel()); + } + + public override void OnData(Slice slice) + { + if (Portfolio.CashBook[Currencies.USD].Amount == 10000) + { + var parameters = new ApplyFundsSettlementModelParameters(Portfolio, _spy, Time, new CashAmount(101, Currencies.USD), null); + _spy.SettlementModel.ApplyFunds(parameters); + } + } + + public override void OnEndOfAlgorithm() + { + if (Portfolio.CashBook[Currencies.USD].Amount != 10101) + { + throw new Exception($"It was expected to have 10101 USD in Portfolio, but was {Portfolio.CashBook[Currencies.USD].Amount}"); + } + + var parameters = new ScanSettlementModelParameters(Portfolio, _spy, new DateTime(2013, 10, 6)); + _spy.SettlementModel.Scan(parameters); + + if (Portfolio.CashBook[Currencies.USD].Amount != 10000) + { + throw new Exception($"It was expected to have 10000 USD in Portfolio, but was {Portfolio.CashBook[Currencies.USD].Amount}"); + } + } + + /// + /// 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, Language.Python }; + + /// + /// Data Points count of all timeslices of algorithm + /// + public long DataPoints => 48; + + /// + /// 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", "0"}, + {"Average Win", "0%"}, + {"Average Loss", "0%"}, + {"Compounding Annual Return", "108.257%"}, + {"Drawdown", "0%"}, + {"Expectancy", "0"}, + {"Net Profit", "1.010%"}, + {"Sharpe Ratio", "10.983"}, + {"Sortino Ratio", "0"}, + {"Probabilistic Sharpe Ratio", "95.977%"}, + {"Loss Rate", "0%"}, + {"Win Rate", "0%"}, + {"Profit-Loss Ratio", "0"}, + {"Alpha", "1.42"}, + {"Beta", "-0.273"}, + {"Annual Standard Deviation", "0.08"}, + {"Annual Variance", "0.006"}, + {"Information Ratio", "-3.801"}, + {"Tracking Error", "0.288"}, + {"Treynor Ratio", "-3.226"}, + {"Total Fees", "$0.00"}, + {"Estimated Strategy Capacity", "$0"}, + {"Lowest Capacity Asset", ""}, + {"Portfolio Turnover", "0%"}, + {"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"} + }; + } + + public class CustomSettlementModel : ISettlementModel + { + private string _currency; + private decimal _amount; + public void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsParameters) + { + _currency = applyFundsParameters.CashAmount.Currency; + _amount = applyFundsParameters.CashAmount.Amount; + applyFundsParameters.Portfolio.CashBook[_currency].AddAmount(_amount); + } + + public void Scan(ScanSettlementModelParameters settlementParameters) + { + if (settlementParameters.UtcTime == new DateTime(2013, 10, 6)) + { + settlementParameters.Portfolio.CashBook[_currency].AddAmount(-_amount); + } + } + } +} diff --git a/Algorithm.Python/CustomSettlementModelRegressionAlgorithm.py b/Algorithm.Python/CustomSettlementModelRegressionAlgorithm.py index c6996da1cc93..b8d070ca4d81 100644 --- a/Algorithm.Python/CustomSettlementModelRegressionAlgorithm.py +++ b/Algorithm.Python/CustomSettlementModelRegressionAlgorithm.py @@ -23,6 +23,9 @@ def Initialize(self): self.SetEndDate(2013,10,11) self.SetCash(10000) self.spy = self.AddEquity("SPY", Resolution.Daily) + self.SetSettlementModel(self.spy) + + def SetSettlementModel(self, security): self.SetBrokerageModel(CustomBrokerageModelWithCustomSettlementModel()) self.updateRequestSubmitted = False @@ -34,15 +37,20 @@ def OnData(self, slice): def OnEndOfAlgorithm(self): if self.Portfolio.CashBook[Currencies.USD].Amount != 10101: raise Exception(f"It was expected to have 10101 USD in Portfolio, but was {self.Portfolio.CashBook[Currencies.USD].Amount}") + parameters = ScanSettlementModelParameters(self.Portfolio, self.spy, datetime(2013, 10, 6)) + self.spy.SettlementModel.Scan(parameters) + if self.Portfolio.CashBook[Currencies.USD].Amount != 10000: + raise Exception(f"It was expected to have 10000 USD in Portfolio, but was {self.Portfolio.CashBook[Currencies.USD].Amount}") class CustomSettlementModel: def ApplyFunds(self, parameters): - currency = parameters.CashAmount.Currency; - amount = parameters.CashAmount.Amount - parameters.Portfolio.CashBook[currency].AddAmount(amount) + self.currency = parameters.CashAmount.Currency; + self.amount = parameters.CashAmount.Amount + parameters.Portfolio.CashBook[self.currency].AddAmount(self.amount) def Scan(self, parameters): - pass + if parameters.UtcTime == datetime(2013, 10, 6): + parameters.Portfolio.CashBook[self.currency].AddAmount(-self.amount) class CustomBrokerageModelWithCustomSettlementModel(CustomBrokerageModel): def GetSettlementModel(self, security): diff --git a/Algorithm.Python/SetCustomSettlementModelRegressionAlgorithm.py b/Algorithm.Python/SetCustomSettlementModelRegressionAlgorithm.py new file mode 100644 index 000000000000..02e688fd955e --- /dev/null +++ b/Algorithm.Python/SetCustomSettlementModelRegressionAlgorithm.py @@ -0,0 +1,10 @@ +from AlgorithmImports import * +from CustomSettlementModelRegressionAlgorithm import CustomSettlementModel, CustomSettlementModelRegressionAlgorithm + +### +### Regression algorithm to test we can specify a custom settlement model using Security.SetSettlementModel() method +### (without a custom brokerage model) +### +class SetCustomSettlementModelRegressionAlgorithm(CustomSettlementModelRegressionAlgorithm): + def SetSettlementModel(self, security): + security.SetSettlementModel(CustomSettlementModel()) diff --git a/Common/Securities/Security.cs b/Common/Securities/Security.cs index ab50b4ef644d..539cf2fe3919 100644 --- a/Common/Securities/Security.cs +++ b/Common/Securities/Security.cs @@ -720,6 +720,24 @@ public void SetFillModel(PyObject fillModel) FillModel = new FillModelPythonWrapper(fillModel); } + /// + /// Sets the settlement model + /// + /// Model that represents a settlement model + public void SetSettlementModel(ISettlementModel settlementModel) + { + SettlementModel = settlementModel; + } + + /// + /// Sets the settlement model + /// + /// Model that represents a settlement model + public void SetSettlementModel(PyObject settlementModel) + { + SettlementModel = new SettlementModelPythonWrapper(settlementModel); + } + /// /// Sets the slippage model ///