From cdeb2e1fcbeeccc847c165aefdce9efef79dec6a Mon Sep 17 00:00:00 2001 From: Martin-Molinero Date: Tue, 20 Jul 2021 12:50:03 -0300 Subject: [PATCH] Convert AlphaStreamsPortfolio to data source --- .../AlphaStreamsBasicTemplateAlgorithm.cs | 186 +++++++++++++++ .../AlphaStreamsPortfolioState.cs | 220 ++++++++++++++++++ Common/Packets/AlphaResultPacket.cs | 2 +- .../Securities/AlphaStreamsPortfolioState.cs | 128 ---------- .../623b06b231eb1cc1aa3643a46/20180404.json | 2 + Tests/Common/Util/ExtensionsTests.cs | 1 + 6 files changed, 410 insertions(+), 129 deletions(-) create mode 100644 Algorithm.CSharp/AlphaStreamsBasicTemplateAlgorithm.cs create mode 100644 Common/Data/Custom/AlphaStreams/AlphaStreamsPortfolioState.cs delete mode 100644 Common/Securities/AlphaStreamsPortfolioState.cs create mode 100644 Data/alternative/alphastreams/portfoliostate/623b06b231eb1cc1aa3643a46/20180404.json diff --git a/Algorithm.CSharp/AlphaStreamsBasicTemplateAlgorithm.cs b/Algorithm.CSharp/AlphaStreamsBasicTemplateAlgorithm.cs new file mode 100644 index 000000000..5f0f8406f --- /dev/null +++ b/Algorithm.CSharp/AlphaStreamsBasicTemplateAlgorithm.cs @@ -0,0 +1,186 @@ +/* + * 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 QuantConnect.Data; +using QuantConnect.Util; +using QuantConnect.Orders; +using QuantConnect.Interfaces; +using System.Collections.Generic; +using System.Linq; +using QuantConnect.Data.UniverseSelection; +using QuantConnect.Data.Custom.AlphaStreams; +using QuantConnect.Algorithm.Framework.Alphas; +using QuantConnect.Algorithm.Framework.Execution; +using QuantConnect.Algorithm.Framework.Portfolio; + +namespace QuantConnect.Algorithm.CSharp +{ + /// + /// Example algorithm consuming an alpha streams portfolio state and trading based on it + /// + public class AlphaStreamsBasicTemplateAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition + { + private List _currentSymbols; + + /// + /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized. + /// + public override void Initialize() + { + SetStartDate(2018, 04, 04); + SetEndDate(2018, 04, 06); + + _currentSymbols = new List(); + SetExecution(new ImmediateExecutionModel()); + Settings.MinimumOrderMarginPortfolioPercentage = 0.01m; + SetPortfolioConstruction(new SecurityTargetPortfolioConstructionModel()); + var alpha = AddData("623b06b231eb1cc1aa3643a46"); + } + + /// + /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. + /// + /// Slice object keyed by symbol containing the stock data + public override void OnData(Slice data) + { + if (data.ContainsKey("623b06b231eb1cc1aa3643a46")) + { + var portfolioState = (AlphaStreamsPortfolioState)data["623b06b231eb1cc1aa3643a46"]; + var newSymbols = new List(); + if (!portfolioState.PositionGroups.IsNullOrEmpty()) + { + var portfolioValueFactor = Portfolio.TotalPortfolioValue / portfolioState.TotalPortfolioValue * 1; + foreach (var positionGroup in portfolioState.PositionGroups) + { + foreach (var position in positionGroup.Positions) + { + var security = AddSecurity(position.Symbol, Resolution.Minute); + security.Holdings.Target = new PortfolioTarget(position.Symbol, position.Quantity * portfolioValueFactor); + newSymbols.Add(position.Symbol); + _currentSymbols.Remove(position.Symbol); + } + } + } + + foreach (var symbol in _currentSymbols) + { + Securities[symbol].Holdings.Target = null; + Liquidate(symbol); + RemoveSecurity(symbol); + } + + _currentSymbols = newSymbols; + } + } + + public override void OnOrderEvent(OrderEvent orderEvent) + { + Debug($"OnOrderEvent: {orderEvent}"); + } + + public override void OnEndOfAlgorithm() + { + if (Portfolio.Invested) + { + throw new Exception("Should not be invested at end of algorithm"); + } + } + + private class SecurityTargetPortfolioConstructionModel : IPortfolioConstructionModel + { + public IEnumerable CreateTargets(QCAlgorithm algorithm, Insight[] insights) + { + foreach (var symbol in algorithm.Securities.Keys.Where(symbol => symbol.SecurityType == SecurityType.Base)) + { + if (algorithm.CurrentSlice.ContainsKey(symbol)) + { + var portfolioState = (AlphaStreamsPortfolioState)algorithm.CurrentSlice["623b06b231eb1cc1aa3643a46"]; + } + } + + foreach (var security in algorithm.Securities.Values) + { + if (security.Holdings.Target != null && security.Holdings.Target.Quantity != security.Holdings.Quantity) + { + yield return security.Holdings.Target; + } + } + } + public void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) + { + } + } + + /// + /// 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 }; + + /// + /// 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.23%"}, + {"Compounding Annual Return", "-27.348%"}, + {"Drawdown", "0.300%"}, + {"Expectancy", "-1"}, + {"Net Profit", "-0.233%"}, + {"Sharpe 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.474"}, + {"Tracking Error", "0.339"}, + {"Treynor Ratio", "0"}, + {"Total Fees", "$0.00"}, + {"Estimated Strategy Capacity", "$83000.00"}, + {"Lowest Capacity Asset", "BTCUSD XJ"}, + {"Fitness Score", "0.034"}, + {"Kelly Criterion Estimate", "0"}, + {"Kelly Criterion Probability Value", "0"}, + {"Sortino Ratio", "79228162514264337593543950335"}, + {"Return Over Maximum Drawdown", "-127.431"}, + {"Portfolio Turnover", "0.069"}, + {"Total Insights Generated", "0"}, + {"Total Insights Closed", "0"}, + {"Total Insights Analysis Completed", "0"}, + {"Long Insight Count", "0"}, + {"Short Insight Count", "0"}, + {"Long/Short Ratio", "100%"}, + {"Estimated Monthly Alpha Value", "$0"}, + {"Total Accumulated Estimated Alpha Value", "$0"}, + {"Mean Population Estimated Insight Value", "$0"}, + {"Mean Population Direction", "0%"}, + {"Mean Population Magnitude", "0%"}, + {"Rolling Averaged Population Direction", "0%"}, + {"Rolling Averaged Population Magnitude", "0%"}, + {"OrderListHash", "d10390e3426c62b1dc637b7b893e34b6"} + }; + } +} diff --git a/Common/Data/Custom/AlphaStreams/AlphaStreamsPortfolioState.cs b/Common/Data/Custom/AlphaStreams/AlphaStreamsPortfolioState.cs new file mode 100644 index 000000000..cbff21c9b --- /dev/null +++ b/Common/Data/Custom/AlphaStreams/AlphaStreamsPortfolioState.cs @@ -0,0 +1,220 @@ +/* + * 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 System.IO; +using Newtonsoft.Json; +using QuantConnect.Securities; +using System.Collections.Generic; +using QuantConnect.Securities.Positions; + +namespace QuantConnect.Data.Custom.AlphaStreams +{ + /// + /// Snapshot of an algorithms portfolio state + /// + public class AlphaStreamsPortfolioState : BaseData + { + /// + /// The deployed alpha id. This is the id generated upon submission to the alpha marketplace + /// + [JsonProperty("alphaId", DefaultValueHandling = DefaultValueHandling.Ignore)] + public string AlphaId { get; set; } + + /// + /// The algorithm's unique deploy identifier + /// + [JsonProperty("algorithmId", DefaultValueHandling = DefaultValueHandling.Ignore)] + public string AlgorithmId { get; set; } + + /// + /// The source of this data point, 'live trading' or in sample + /// + public string Source { get; set; } + + /// + /// Portfolio state id + /// + public int Id { get; set; } + + /// + /// Algorithms account currency + /// + public string AccountCurrency { get; set; } + + /// + /// The current total portfolio value + /// + public decimal TotalPortfolioValue { get; set; } + + /// + /// The margin used + /// + public decimal TotalMarginUsed { get; set; } + + /// + /// The different positions groups + /// + [JsonProperty("positionGroups", DefaultValueHandling = DefaultValueHandling.Ignore)] + public List PositionGroups { get; set; } + + /// + /// Gets the cash book that keeps track of all currency holdings (only settled cash) + /// + [JsonProperty("cashBook", DefaultValueHandling = DefaultValueHandling.Ignore)] + public Dictionary CashBook { get; set; } + + /// + /// Gets the cash book that keeps track of all currency holdings (only unsettled cash) + /// + [JsonProperty("unsettledCashBook", DefaultValueHandling = DefaultValueHandling.Ignore)] + public Dictionary UnsettledCashBook { get; set; } + + /// + /// Return the Subscription Data Source + /// + /// Configuration object + /// Date of this source file + /// true if we're in live mode, false for backtesting mode + /// Subscription Data Source. + public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode) + { + var source = Path.Combine( + Globals.DataFolder, + "alternative", + "alphastreams", + "portfoliostate", + config.Symbol.Value.ToLowerInvariant(), + $"{date:yyyyMMdd}.json" + ); + return new SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile, FileFormat.Csv); + } + + /// + /// Reader converts each line of the data source into BaseData objects. + /// + /// Subscription data config setup object + /// Content of the source document + /// Date of the requested data + /// true if we're in live mode, false for backtesting mode + /// New data point object + public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode) + { + var dataPoint = JsonConvert.DeserializeObject(line); + dataPoint.Symbol = config.Symbol; + return dataPoint; + } + + /// + /// Specifies the data time zone for this data type + /// + /// Will throw for security types + /// other than + /// The of this data type + public override DateTimeZone DataTimeZone() + { + return DateTimeZone.Utc; + } + + /// + /// Return a new instance clone of this object, used in fill forward + /// + public override BaseData Clone() + { + return new AlphaStreamsPortfolioState + { + Id = Id, + Time = Time, + Source = Source, + Symbol = Symbol, + AlphaId = AlphaId, + DataType = DataType, + CashBook = CashBook, + AlgorithmId = AlgorithmId, + PositionGroups = PositionGroups, + TotalMarginUsed = TotalMarginUsed, + AccountCurrency = AccountCurrency, + UnsettledCashBook = UnsettledCashBook, + TotalPortfolioValue = TotalPortfolioValue, + }; + } + + /// + /// Indicates that the data set is expected to be sparse + /// + public override bool IsSparseData() + { + return true; + } + } + + /// + /// Snapshot of a position group state + /// + public class PositionGroupState + { + /// + /// Currently margin used + /// + public decimal MarginUsed { get; set; } + + /// + /// The margin used by this position in relation to the total portfolio value + /// + public decimal PortfolioValuePercentage { get; set; } + + /// + /// THe positions which compose this group + /// + public List Positions { get; set; } + } + + /// + /// Snapshot of a position state + /// + public class PositionState : IPosition + { + /// + /// The symbol + /// + public Symbol Symbol { get; set; } + + /// + /// The quantity + /// + public decimal Quantity { get; set; } + + /// + /// The unit quantity. The unit quantities of a group define the group. For example, a covered + /// call has 100 units of stock and -1 units of call contracts. + /// + public decimal UnitQuantity { get; set; } + + /// + /// Creates a new instance + /// + public static PositionState Create(IPosition position) + { + return new PositionState + { + Symbol = position.Symbol, + Quantity = position.Quantity, + UnitQuantity = position.UnitQuantity + }; + } + } +} diff --git a/Common/Packets/AlphaResultPacket.cs b/Common/Packets/AlphaResultPacket.cs index 0192a4e31..a65aa479e 100644 --- a/Common/Packets/AlphaResultPacket.cs +++ b/Common/Packets/AlphaResultPacket.cs @@ -16,8 +16,8 @@ using Newtonsoft.Json; using QuantConnect.Orders; -using QuantConnect.Securities; using System.Collections.Generic; +using QuantConnect.Data.Custom.AlphaStreams; using QuantConnect.Algorithm.Framework.Alphas; namespace QuantConnect.Packets diff --git a/Common/Securities/AlphaStreamsPortfolioState.cs b/Common/Securities/AlphaStreamsPortfolioState.cs deleted file mode 100644 index b0d00296a..000000000 --- a/Common/Securities/AlphaStreamsPortfolioState.cs +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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 Newtonsoft.Json; -using System.Collections.Generic; -using QuantConnect.Securities.Positions; - -namespace QuantConnect.Securities -{ - /// - /// Snapshot of an algorithms portfolio state - /// - public class AlphaStreamsPortfolioState - { - /// - /// Portfolio state id - /// - public int Id { get; set; } - - /// - /// Algorithms account currency - /// - public string AccountCurrency { get; set; } - - /// - /// The utc time this state was captured - /// - public DateTime UtcTime { get; set; } - - /// - /// The current total portfolio value - /// - public decimal TotalPortfolioValue { get; set; } - - /// - /// The margin used - /// - public decimal TotalMarginUsed { get; set; } - - /// - /// The different positions groups - /// - [JsonProperty("positionGroups", DefaultValueHandling = DefaultValueHandling.Ignore)] - public List PositionGroups { get; set; } - - /// - /// Gets the cash book that keeps track of all currency holdings (only settled cash) - /// - [JsonProperty("cashBook", DefaultValueHandling = DefaultValueHandling.Ignore)] - public Dictionary CashBook { get; set; } - - /// - /// Gets the cash book that keeps track of all currency holdings (only unsettled cash) - /// - [JsonProperty("unsettledCashBook", DefaultValueHandling = DefaultValueHandling.Ignore)] - public Dictionary UnsettledCashBook { get; set; } - } - - /// - /// Snapshot of a position group state - /// - public class PositionGroupState - { - /// - /// Currently margin used - /// - public decimal MarginUsed { get; set; } - - /// - /// The margin used by this position in relation to the total portfolio value - /// - public decimal PortfolioValuePercentage { get; set; } - - /// - /// THe positions which compose this group - /// - public List Positions { get; set; } - } - - /// - /// Snapshot of a position state - /// - public class PositionState : IPosition - { - /// - /// The symbol - /// - public Symbol Symbol { get; set; } - - /// - /// The quantity - /// - public decimal Quantity { get; set; } - - /// - /// The unit quantity. The unit quantities of a group define the group. For example, a covered - /// call has 100 units of stock and -1 units of call contracts. - /// - public decimal UnitQuantity { get; set; } - - /// - /// Creates a new instance - /// - public static PositionState Create(IPosition position) - { - return new PositionState - { - Symbol = position.Symbol, - Quantity = position.Quantity, - UnitQuantity = position.UnitQuantity - }; - } - } -} diff --git a/Data/alternative/alphastreams/portfoliostate/623b06b231eb1cc1aa3643a46/20180404.json b/Data/alternative/alphastreams/portfoliostate/623b06b231eb1cc1aa3643a46/20180404.json new file mode 100644 index 000000000..5befebed1 --- /dev/null +++ b/Data/alternative/alphastreams/portfoliostate/623b06b231eb1cc1aa3643a46/20180404.json @@ -0,0 +1,2 @@ +{"AlphaId":"623b06b231eb1cc1aa3643a46","AlgorithmId":"37b0922b-54d0-44bc-8dfb-b90ee4554884","Source":"live trading","AccountCurrency":"USD","TotalPortfolioValue":100000.0,"TotalMarginUsed":1.0,"Time":"2018-04-04T08:03:58.3653852Z","CashBook":{"USD":{"SecuritySymbols":[],"Symbol":"USD","Amount":10.0,"ConversionRate":1.0,"CurrencySymbol":"$","ValueInAccountCurrency":10.0},"EUR":{"SecuritySymbols":[],"Symbol":"EUR","Amount":1.0,"ConversionRate":1.2,"CurrencySymbol":"€","ValueInAccountCurrency":1.2}},"UnsettledCashBook":{"USD":{"SecuritySymbols":[],"Symbol":"USD","Amount":1.0,"ConversionRate":1.0,"CurrencySymbol":"$","ValueInAccountCurrency":1.0}},"PositionGroups":[{"MarginUsed":11.0,"PortfolioValuePercentage":0.1,"Positions":[{"Symbol":{"Value":"BTCUSD","ID":"BTCUSD XJ","Permtick":"BTCUSD"},"Quantity":0.999,"UnitQuantity":0.00000001}]}]} +{"AlphaId":"623b06b231eb1cc1aa3643a46","AlgorithmId":"ba29373c-a1b4-4e45-a587-e31fb02a3557","Source":"live trading","AccountCurrency":"USD","TotalPortfolioValue":100000.0,"TotalMarginUsed":0.0,"Time":"2018-04-04T21:03:58.3782404Z","CashBook":{"USD":{"SecuritySymbols":[],"Symbol":"USD","Amount":10.0,"ConversionRate":1.0,"CurrencySymbol":"$","ValueInAccountCurrency":10.0},"EUR":{"SecuritySymbols":[],"Symbol":"EUR","Amount":1.0,"ConversionRate":1.2,"CurrencySymbol":"€","ValueInAccountCurrency":1.2}},"UnsettledCashBook":{},"PositionGroups":[]} diff --git a/Tests/Common/Util/ExtensionsTests.cs b/Tests/Common/Util/ExtensionsTests.cs index b5540ba39..ad64994a6 100644 --- a/Tests/Common/Util/ExtensionsTests.cs +++ b/Tests/Common/Util/ExtensionsTests.cs @@ -25,6 +25,7 @@ using QuantConnect.Algorithm; using QuantConnect.Algorithm.Framework.Alphas; using QuantConnect.Data; using QuantConnect.Data.Auxiliary; +using QuantConnect.Data.Custom.AlphaStreams; using QuantConnect.Data.Market; using QuantConnect.Data.UniverseSelection; using QuantConnect.Indicators;