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;