Compare commits

...

34 Commits
13281 ... 13402

Author SHA1 Message Date
Alexandre Catarino
3d3733c0fb Adds Market.HKFE to InteractiveBrokersFeeModel (#6127)
Adds `Market.HKFE` to `InteractiveBrokersFeeModel` in the Futures Options case.
2021-12-22 19:32:07 -03:00
Martin-Molinero
1303ccf843 Update readme.md 2021-12-22 17:16:41 -03:00
Martin-Molinero
3b5f3fcf42 Update readme.md 2021-12-22 16:18:09 -03:00
Andreas Sundebo
e2de241c2b Feature 5090 add api optimization methods (#6108)
* Move Optimizer-related DTOs and JSON converters into Common/Optimizer

* Add REST methods for Optimization

* Move OptimizationStatus into Common

* Change optimizationId parameter type to string

* Update Optimization and add lightweight optimization object

* Rename lightweight optimization to BaseOptimization and remove unneccessary properties

* Remove snapshotId from Optimization, add ParameterSet to Backtest

* Add missing IApi.cs method signatures

* Move ParameterSet into Common

* Replace Backtest with OptimizationBacktest

* Update UpdateOptimization to not include null or empty name and layout params in the request

* Change Objective targetTemplate regex pattern from ['(.+)'] to (.+) to prevent escaping target strings without whitespace

* Return Estimate object when calling EstimateOptimization

* Use DefaultNamingStrategy when serializing constraint operators

* Revert "Change Objective targetTemplate regex pattern from ['(.+)'] to (.+) to prevent escaping target strings without whitespace"

This reverts commit fbe7de0fd7.

* Update Api method signatures

* Add unit tests

* Fix XML comment referring to the old class name

* Fix XML summary for OptimizationResponseWrapper

* Address review feedback
- Remove unused testOrganizationId
- Change NodeType from string to NodeType enum
- Clarify unit types for Estimate time and balance
- Simplify JsonConverter classes

* Add accessors to Common/Api classes

* Define performance metrics names in PerformanceMetrics class

* Remove unnecessary branching logic from GetSeriesValues method

* Add crefs and examples to XML comments in the Api class

* Revert "Change NodeType from string to NodeType enum"

* Remove layout param from UpdateOptimization method

* Backtest property ParameterSet should be of type ParameterSet

* Add asserts for deserialization in OptimizationBacktestJsonConverterTests

* Replace the three target-related properties with Criterion

* Add serialization and deserialization tests for Optimization

* Remove Optimization Serialization test

* Add EstimateDeserialization test

* Add asserts for integration tests

* Address self review

* Revert test case

* Update Nodes.cs

* Update Nodes.cs

* Set Aborted status when Optimization fails to start

* Add ParameterSetJsonConverter and ParameterSetJsonConverterTests

Co-authored-by: Martin-Molinero <martin@quantconnect.com>
2021-12-22 13:14:56 -03:00
Martin-Molinero
68e2a9170a Do not send internal SecurityChanges to Algorithm (#6118)
* Do not send internal SecurityChanges to Algorithm

- Will not send internal security changes to the Algorithm by default.
  Following custom security changes filter pattern. Updating regression
  algorithms to assert behavior.
- The universe member will know wether it was added with internal
  configurations or not

* Address reviews use a separate collection for internals

* Refactor solution. Adding security changes constructor class
2021-12-21 20:24:32 -03:00
Adalyat Nazirov
d395f704b3 Bug 6115 adjust dates (#6124)
* GH-6115: adjust dates

* fix

* use another approach

* Add lean data writter multiple days data unit test

Co-authored-by: Martin-Molinero <martin@quantconnect.com>
2021-12-21 17:33:36 -03:00
Martin-Molinero
4d1fc7e05a Handle security added and removed in the same loop (#6120)
* Handle security added and removed in the same loop

- Correctly handle adding and removing a security in the same loop.
  Adding regression test

* Adding comments
2021-12-21 11:59:45 -03:00
Martin-Molinero
e3a562d3c9 Add file and line number to documentation attribute (#6122) 2021-12-20 17:30:04 -08:00
Martin-Molinero
4fdd60d146 Use 64 when saving zips update dotnetZip (#6114) 2021-12-20 16:39:06 -03:00
Martin-Molinero
abbb50e209 Minor improvements for data reading and caching (#6113)
* Minor improvements for data reading and caching

* Address reviews

* Adjust zip cache error check
2021-12-16 19:58:37 -03:00
Alexandre Catarino
0e1cc288a6 Change Default Market of CFD to OANDA (#6107)
Oanda is currently the only provider.
2021-12-13 17:58:57 -03:00
Martin-Molinero
3b826535c7 Fix for ConcurrentDictionary Thread Safety (#6105)
- ConcurrentDictionary with OrderBy is not thread safe, adding thread
  safe extension method. Adding unit tests
2021-12-13 10:45:58 -03:00
Martin-Molinero
59da486e30 IB will correctly create non USD currency contract (#6103)
- IB will create contract based on SPDB entry for symbol. Adding unit
  test
2021-12-10 13:56:32 -03:00
Martin-Molinero
f42d7bb3a2 Align universe security and configuration TZ (#6102)
* Align universe security and configuration TZ

- Make sure universe security and configuration tz are aligned always.
  Adding unit test reproducing issue

* Address review UserDefinedUniverse will use UTC TZ
2021-12-09 15:53:56 -03:00
Martin-Molinero
87bd0d7792 CompositeDataQueueHandler handles duplicate configs (#6101)
* CompositeDataQueueHandler handles duplicate configs

- CompositeDataQueueHandler will handle duplicate subscriptions sharing
  the same config. Adding unit tests

* Refactor bug solution after review

- LiveSubscriptionEnumerator will not long perform any symbol mapping
  but will just trigger a new subscription call when remapped.
- CompositeDHQ will handling symbol mapping and keep track of these
  mapped configs to trigger unsubscribe accordengly. Adding unit tests

* Adjust solution after review

- To avoid breaking uniqueness of SubscriptionDataConfig will be adding
  a private `mapped` property that will change equality of mapped
  configs to avoid them clashing. Adding unit tests

* Rename IDQH subscription extension methods
2021-12-09 14:53:04 -03:00
Louis Szeto
8ca9258e70 API Reference for docs v2 (#6098)
API Reference for docs v2 

Co-authored-by: Alexandre Catarino <AlexCatarino@users.noreply.github.com>
2021-12-08 16:25:36 -08:00
Martin-Molinero
72105539fc Minor Exchanges cleanup (#6100) 2021-12-06 19:27:27 -03:00
Anuj Patel
589e8a9293 fix Kraken fee model (#6096)
* Update KrakenFeeModel.cs

* Update KrakenFeeModelTests.cs

Co-authored-by: Anuj Patel <91538343+anuj-mitul-patel@users.noreply.github.com>
2021-12-06 11:59:20 -03:00
Martin-Molinero
dd27a382f7 Composite data queue handler IUniverseProvider (#6097)
* Minor performance improvements

* CompositeDataQueueHandler is UniverseProvider

- CompositeDataQueueHandler implements the UniverseProvider interface.
  Adding unit tests
2021-12-06 10:27:18 -03:00
Jovad Uribe
62a8aee38c Kaufman Efficiency Ratio Indicator (#6050)
* Indicator

* Fixed logic error

* Removed old files, added KER into KAMA

* Removed old comments

* Added requested changes

* Minor clean up

* Refactors KaufmanEfficiencyRatio and KaufmanAdaptiveMovingAverage

Co-authored-by: Martin-Molinero <martin@quantconnect.com>
Co-authored-by: Alexandre Catarino <AlexCatarino@users.noreply.github.com>
2021-12-04 18:55:09 -03:00
Alexandre Catarino
7e7c27416b Updates KeltnerChannels to Update MiddleBand with EndTime (#6084)
* Updates KeltnerChannels to Update MiddleBand with EndTime

* Adds Unit Test

This unit test shows that the timestamp of the MiddleBand and the indication are aligned as expected.
2021-12-03 19:43:32 -03:00
Martin-Molinero
26f2f88c67 Add documentation attribute default value (#6095) 2021-12-03 18:47:47 -03:00
Martin-Molinero
c08c129860 Add documentation attribute (#6094) 2021-12-03 18:23:06 -03:00
Martin-Molinero
bae10389ae Update readme.md 2021-12-03 17:15:58 -03:00
Martin-Molinero
4301d7cead Update readme.md 2021-12-03 17:08:06 -03:00
Martin-Molinero
d49f1d0d6c Update readme.md 2021-12-03 16:34:47 -03:00
Ronit Jain
264c3c8374 Composite IDQH - Support multiple live data feeds (#6047)
* initial commit

* Follow IDQH implementation

* Expect a list of data handlers from LiveNodePacket

* Return null if can not subscribe

* refctor to add check for subscription

* initialze null

* Add tests

* Check subscribe retuns null/not-null

* cleanup

* Read all required IDQH credentails to job

* Use CDQH to handle all IDQH instances

* constructor abstraction to call from setjob

* use flag

* remove redundant because derived will call initialize on it

* abstract and initialize from setjob

* handle null enumerators

* get creds from data handlers

* handle single data handler value from data-queue-handler

* Fix to support a json array

* Fix missed constructor call

* change access modifier to access from Tests files

* Add test to get brokerageFactory from dataQueueHandler

* Fix init flag to handle all conditions

* Add docs

* initialize from setjob

* Check if websocket open before using

* change defination of initialzie to include tradier

* clean up

* change defination

* fix wrong api key name

* return empty enumerator

* check websocket open before sending request

* check connection before subscribing

* fix to include more cases

* check websocket open before sending request

* Minor refactoring

* reafctor and use IsConnected

* remove unused

* clean up

* Fix test cases

* reverse change

* include config changes

* connect to websocket from setjob

* check websocket connection from setjob

* clean up

* include condition for IDQH that are not brokerage

* Address review

* Add market check condition before subscribe

* Remove deprecated

* Minor fix for deserializing data queue handler

Co-authored-by: Martin-Molinero <martin@quantconnect.com>
2021-12-03 16:18:41 -03:00
Martin-Molinero
8a1f67edfc Minor fixes (#6093)
- Update Atreyu fees
- Remove redundant check in AlphaStreamBrokerageModel
- Fix option contract removal and second addition. Adding unit test
2021-12-03 12:54:49 -03:00
Martin-Molinero
5f434f2fa5 SetupHandlers will exit if errors on initialize (#6092)
- SetupHandlers will exit right away if detect errors on initialize.
  Adding unit tests
2021-12-02 19:24:51 -03:00
Martin-Molinero
e37f8ae878 Fix for adding continuous future and future contract at the same time (#6091)
- Fix for adding continuous future and manually adding contract at the
  same time. Continuous future was using the user defined universe
  symbol and caused clashes. Adding regression test reproducing the issue.
2021-12-02 18:13:52 -03:00
Martin-Molinero
b4e95209f6 Fix for IB Option position race condition (#6090)
- Fix for IB option position update race condition, where the BTH would
  incorrectly assume it should trigger an early option assignment. Adding unit tests
2021-12-02 17:09:50 -03:00
Martin-Molinero
ea65c61dc8 Minor InteractiveBrokers fix (#6089)
- IB needs to notify the `DefaultBrokerageMessageHandler` we have re
  connected else it might kill the algorithm
2021-12-01 19:26:25 -03:00
Ricardo Andrés Marino Rojas
6bf6ff1a6a Fix bug in ConsumeMultipleMinutes() test (#6083)
* Give `code()` more time per iteration

* Another proposed solution

* Revert "Another proposed solution"

This reverts commit 29bf5a7554.

* Add an AutoResetEvent field in `TimeConsumer()`

* Avoid change TimeMonitor implementation

* Remove changes in `TimeConsumer.cs`

* Requested changes

* Avoid re-implementation
2021-11-30 21:44:42 -03:00
Martin-Molinero
d1a35e6281 Continuous Futures Refactor. Live Mappings (#6076)
* Continuous Futures Refactor. Live Mappings

- Adding support for live mappings. LiveTradingDataFeed will handle any
  symbol mapping at the configuration layer and resubscribe through the
  IDQH
- Refactoring continuous futures adding ContinuousFutureUniverse that
  will select the currently mapped security

* Minor fixes

- Remove addition of configurations in UniverseSelection step, leave
  resposability for universe.
- LiveTradingDF future unit test will only assert slice data for non
  internal feeds.
- ContinuousContractUniverse will respect internal option interest
  subscription

* Address review
2021-11-30 21:38:50 -03:00
188 changed files with 6907 additions and 1434 deletions

View File

@@ -0,0 +1,131 @@
/*
* 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 System.Linq;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm reproducing GH issue #5971 where we add and remove an option in the same loop
/// </summary>
public class AddAndRemoveSecuritySameLoopRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _contract;
private bool _hasRemoved;
public override void Initialize()
{
SetStartDate(2014, 06, 06);
SetEndDate(2014, 06, 09);
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
UniverseSettings.MinimumTimeInUniverse = TimeSpan.Zero;
var aapl = AddEquity("AAPL").Symbol;
_contract = OptionChainProvider.GetOptionContractList(aapl, Time)
.OrderBy(symbol => symbol.ID.Symbol)
.FirstOrDefault(optionContract => optionContract.ID.OptionRight == OptionRight.Call
&& optionContract.ID.OptionStyle == OptionStyle.American);
}
public override void OnData(Slice slice)
{
if (_hasRemoved)
{
throw new Exception("Expect a single call to OnData where we removed the option and underlying");
}
_hasRemoved = true;
AddOptionContract(_contract);
// changed my mind!
RemoveOptionContract(_contract);
RemoveSecurity(_contract.Underlying);
RemoveSecurity(AddEquity("SPY", Resolution.Daily).Symbol);
}
public override void OnEndOfAlgorithm()
{
if (!_hasRemoved)
{
throw new Exception("We did not remove the option contract!");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public Language[] Languages { get; } = { Language.CSharp };
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Trades", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "-9.486"},
{"Tracking Error", "0.008"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Fitness Score", "0"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "79228162514264337593543950335"},
{"Return Over Maximum Drawdown", "79228162514264337593543950335"},
{"Portfolio Turnover", "0"},
{"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", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}

View File

@@ -0,0 +1,165 @@
/*
* 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 System.Linq;
using QuantConnect.Data;
using QuantConnect.Orders;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using System.Collections.Generic;
using QuantConnect.Securities.Future;
using QuantConnect.Data.UniverseSelection;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Continuous Futures Regression algorithm. Asserting and showcasing the behavior of adding a continuous future
/// and a future contract at the same time
/// </summary>
public class AddFutureContractWithContinuousRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _currentMappedSymbol;
private Future _continuousContract;
private Future _futureContract;
private bool _ended;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 6);
SetEndDate(2013, 10, 10);
_continuousContract = AddFuture(Futures.Indices.SP500EMini,
dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
dataMappingMode: DataMappingMode.LastTradingDay,
contractDepthOffset: 0
);
_futureContract = AddFutureContract(FutureChainProvider.GetFutureContractList(_continuousContract.Symbol, Time).First());
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice data)
{
if (_ended)
{
throw new Exception($"Algorithm should of ended!");
}
if (data.Keys.Count > 2)
{
throw new Exception($"Getting data for more than 2 symbols! {string.Join(",", data.Keys.Select(symbol => symbol))}");
}
if (UniverseManager.Count != 3)
{
throw new Exception($"Expecting 3 universes (chain, continuous and user defined) but have {UniverseManager.Count}");
}
if (!Portfolio.Invested)
{
Buy(_futureContract.Symbol, 1);
Buy(_continuousContract.Mapped, 1);
RemoveSecurity(_futureContract.Symbol);
RemoveSecurity(_continuousContract.Symbol);
_ended = true;
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status == OrderStatus.Filled)
{
Log($"{orderEvent}");
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
Debug($"{Time}-{changes}");
if (changes.AddedSecurities.Any(security => security.Symbol != _continuousContract.Symbol && security.Symbol != _futureContract.Symbol)
|| changes.RemovedSecurities.Any(security => security.Symbol != _continuousContract.Symbol && security.Symbol != _futureContract.Symbol))
{
throw new Exception($"We got an unexpected security changes {changes}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public Language[] Languages { get; } = { Language.CSharp };
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Trades", "3"},
{"Average Win", "0%"},
{"Average Loss", "-0.03%"},
{"Compounding Annual Return", "-2.503%"},
{"Drawdown", "0.000%"},
{"Expectancy", "-1"},
{"Net Profit", "-0.032%"},
{"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", "-0.678"},
{"Tracking Error", "0.243"},
{"Treynor Ratio", "0"},
{"Total Fees", "$7.40"},
{"Estimated Strategy Capacity", "$2100000.00"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Fitness Score", "0.419"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "79228162514264337593543950335"},
{"Return Over Maximum Drawdown", "-81.557"},
{"Portfolio Turnover", "0.837"},
{"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", "68775c18eb40c1bde212653faec4016e"}
};
}
}

View File

@@ -0,0 +1,165 @@
/*
* 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 System.Linq;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm reproducing GH issue #6073 where we remove and re add an option and expect it to work
/// </summary>
public class AddOptionContractTwiceRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _contract;
private bool _hasRemoved;
private bool _reAdded;
public override void Initialize()
{
SetStartDate(2014, 06, 06);
SetEndDate(2014, 06, 09);
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
UniverseSettings.MinimumTimeInUniverse = TimeSpan.Zero;
UniverseSettings.FillForward = false;
AddEquity("SPY", Resolution.Daily);
var aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
_contract = OptionChainProvider.GetOptionContractList(aapl, Time)
.OrderBy(symbol => symbol.ID.Symbol)
.FirstOrDefault(optionContract => optionContract.ID.OptionRight == OptionRight.Call
&& optionContract.ID.OptionStyle == OptionStyle.American);
AddOptionContract(_contract);
}
public override void OnData(Slice slice)
{
if (_hasRemoved)
{
if (!_reAdded && slice.ContainsKey(_contract) && slice.ContainsKey(_contract.Underlying))
{
throw new Exception("Getting data for removed option and underlying!");
}
if (!Portfolio.Invested && _reAdded)
{
var option = Securities[_contract];
var optionUnderlying = Securities[_contract.Underlying];
if (option.IsTradable && optionUnderlying.IsTradable
&& slice.ContainsKey(_contract) && slice.ContainsKey(_contract.Underlying))
{
Buy(_contract, 1);
}
}
if (!Securities[_contract].IsTradable
&& !Securities[_contract.Underlying].IsTradable
&& !_reAdded)
{
// ha changed my mind!
AddOptionContract(_contract);
_reAdded = true;
}
}
if (slice.ContainsKey(_contract) && slice.ContainsKey(_contract.Underlying))
{
if (!_hasRemoved)
{
RemoveOptionContract(_contract);
RemoveSecurity(_contract.Underlying);
_hasRemoved = true;
}
}
}
public override void OnEndOfAlgorithm()
{
if (!_hasRemoved)
{
throw new Exception("We did not remove the option contract!");
}
if (!_reAdded)
{
throw new Exception("We did not re add the option contract!");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public Language[] Languages { get; } = { Language.CSharp };
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Trades", "2"},
{"Average Win", "0%"},
{"Average Loss", "-0.05%"},
{"Compounding Annual Return", "-4.548%"},
{"Drawdown", "0.100%"},
{"Expectancy", "-1"},
{"Net Profit", "-0.051%"},
{"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", "-9.486"},
{"Tracking Error", "0.008"},
{"Treynor Ratio", "0"},
{"Total Fees", "$2.00"},
{"Estimated Strategy Capacity", "$30000.00"},
{"Lowest Capacity Asset", "AAPL VXBK4Q9ZIFD2|AAPL R735QTJ8XC9X"},
{"Fitness Score", "0"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "79228162514264337593543950335"},
{"Return Over Maximum Drawdown", "-89.181"},
{"Portfolio Turnover", "0"},
{"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", "7fbcd12db40304d50b3a34d7878eb3cf"}
};
}
}

View File

@@ -86,10 +86,10 @@ namespace QuantConnect.Algorithm.CSharp
{"Total Trades", "2"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "93.443%"},
{"Compounding Annual Return", "93.340%"},
{"Drawdown", "1.100%"},
{"Expectancy", "0"},
{"Net Profit", "0.847%"},
{"Net Profit", "0.846%"},
{"Sharpe Ratio", "6.515"},
{"Probabilistic Sharpe Ratio", "67.535%"},
{"Loss Rate", "0%"},
@@ -102,14 +102,14 @@ namespace QuantConnect.Algorithm.CSharp
{"Information Ratio", "6.515"},
{"Tracking Error", "0.11"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.52"},
{"Total Fees", "$1.20"},
{"Estimated Strategy Capacity", "$8600000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Fitness Score", "0.124"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "79228162514264337593543950335"},
{"Return Over Maximum Drawdown", "78.376"},
{"Return Over Maximum Drawdown", "78.222"},
{"Portfolio Turnover", "0.124"},
{"Total Insights Generated", "0"},
{"Total Insights Closed", "0"},

View File

@@ -0,0 +1,161 @@
/*
* 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.Orders;
using QuantConnect.Interfaces;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
using Futures = QuantConnect.Securities.Futures;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic Continuous Futures Template Algorithm
/// </summary>
public class BasicTemplateContinuousFutureAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Future _continuousContract;
private Security _currentContract;
private SimpleMovingAverage _fast;
private SimpleMovingAverage _slow;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 7, 1);
SetEndDate(2014, 1, 1);
_continuousContract = AddFuture(Futures.Indices.SP500EMini,
dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
dataMappingMode: DataMappingMode.LastTradingDay,
contractDepthOffset: 0
);
_fast = SMA(_continuousContract.Symbol, 3, Resolution.Daily);
_slow = SMA(_continuousContract.Symbol, 10, Resolution.Daily);
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice data)
{
foreach (var changedEvent in data.SymbolChangedEvents.Values)
{
Log($"{Time} - SymbolChanged event: {changedEvent}");
}
if (!Portfolio.Invested)
{
if(_fast > _slow)
{
_currentContract = Securities[_continuousContract.Mapped];
Buy(_currentContract.Symbol, 1);
}
}
else if(_fast < _slow)
{
Liquidate();
}
if (_currentContract != null && _currentContract.Symbol != _continuousContract.Mapped)
{
Log($"{Time} - rolling position from {_currentContract.Symbol} to {_continuousContract.Mapped}");
var currentPositionSize = _currentContract.Holdings.Quantity;
Liquidate(_currentContract.Symbol);
Buy(_continuousContract.Mapped, currentPositionSize);
_currentContract = Securities[_continuousContract.Mapped];
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
Debug($"{orderEvent}");
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
Debug($"{Time}-{changes}");
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Trades", "2"},
{"Average Win", "0%"},
{"Average Loss", "0.00%"},
{"Compounding Annual Return", "-0.007%"},
{"Drawdown", "0.000%"},
{"Expectancy", "-1"},
{"Net Profit", "-0.004%"},
{"Sharpe Ratio", "-0.369"},
{"Probabilistic Sharpe Ratio", "10.640%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "-2.751"},
{"Tracking Error", "0.082"},
{"Treynor Ratio", "-0.616"},
{"Total Fees", "$3.70"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Fitness Score", "0.007"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "79228162514264337593543950335"},
{"Return Over Maximum Drawdown", "-0.738"},
{"Portfolio Turnover", "0.01"},
{"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", "bd7fbe57802dfedb36c85609b7234016"}
};
}
}

View File

@@ -131,30 +131,30 @@ namespace QuantConnect.Algorithm.CSharp
{"Average Win", "0.00%"},
{"Average Loss", "0.00%"},
{"Compounding Annual Return", "-100.000%"},
{"Drawdown", "13.400%"},
{"Drawdown", "13.500%"},
{"Expectancy", "-0.818"},
{"Net Profit", "-13.418%"},
{"Sharpe Ratio", "-321.172"},
{"Net Profit", "-13.517%"},
{"Sharpe Ratio", "-98.781"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "89%"},
{"Win Rate", "11%"},
{"Profit-Loss Ratio", "0.69"},
{"Alpha", "-1.208"},
{"Beta", "0.013"},
{"Annual Standard Deviation", "0.003"},
{"Alpha", "-1.676"},
{"Beta", "0.042"},
{"Annual Standard Deviation", "0.01"},
{"Annual Variance", "0"},
{"Information Ratio", "-71.816"},
{"Tracking Error", "0.24"},
{"Treynor Ratio", "-77.951"},
{"Information Ratio", "-73.981"},
{"Tracking Error", "0.233"},
{"Treynor Ratio", "-23.975"},
{"Total Fees", "$15207.00"},
{"Estimated Strategy Capacity", "$8000.00"},
{"Lowest Capacity Asset", "GC VOFJUCDY9XNH"},
{"Fitness Score", "0.031"},
{"Fitness Score", "0.033"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "-9.206"},
{"Return Over Maximum Drawdown", "-7.871"},
{"Portfolio Turnover", "302.123"},
{"Sortino Ratio", "-8.62"},
{"Return Over Maximum Drawdown", "-7.81"},
{"Portfolio Turnover", "302.321"},
{"Total Insights Generated", "0"},
{"Total Insights Closed", "0"},
{"Total Insights Analysis Completed", "0"},
@@ -168,7 +168,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Mean Population Magnitude", "0%"},
{"Rolling Averaged Population Direction", "0%"},
{"Rolling Averaged Population Magnitude", "0%"},
{"OrderListHash", "9e50b7d8e41033110f927658e731f4c6"}
{"OrderListHash", "35b3f4b7a225468d42ca085386a2383e"}
};
}
}

View File

@@ -37,7 +37,7 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2019, 2, 21);
SetCash("EUR", 100000);
_symbol = AddCfd("DE30EUR", Resolution.Minute, Market.Oanda).Symbol;
_symbol = AddCfd("DE30EUR").Symbol;
SetBenchmark(_symbol);
}

View File

@@ -79,7 +79,7 @@ namespace QuantConnect.Algorithm.CSharp
}
}
if (_lastDateLog.Month != Time.Month)
if (_lastDateLog.Month != Time.Month && _continuousContract.HasData)
{
_lastDateLog = Time;
@@ -88,7 +88,7 @@ namespace QuantConnect.Algorithm.CSharp
{
Liquidate();
}
else if(_continuousContract.HasData)
else
{
// This works because we set this contract as tradable, even if it's a canonical security
Buy(_continuousContract.Symbol, 1);
@@ -138,33 +138,33 @@ namespace QuantConnect.Algorithm.CSharp
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Trades", "2"},
{"Average Win", "1.11%"},
{"Average Win", "1.16%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "2.199%"},
{"Drawdown", "1.700%"},
{"Compounding Annual Return", "2.311%"},
{"Drawdown", "1.600%"},
{"Expectancy", "0"},
{"Net Profit", "1.109%"},
{"Sharpe Ratio", "0.717"},
{"Probabilistic Sharpe Ratio", "38.157%"},
{"Net Profit", "1.159%"},
{"Sharpe Ratio", "0.753"},
{"Probabilistic Sharpe Ratio", "39.483%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.007"},
{"Alpha", "-0.006"},
{"Beta", "0.099"},
{"Annual Standard Deviation", "0.022"},
{"Annual Variance", "0"},
{"Information Ratio", "-2.732"},
{"Tracking Error", "0.076"},
{"Treynor Ratio", "0.156"},
{"Treynor Ratio", "0.165"},
{"Total Fees", "$3.70"},
{"Estimated Strategy Capacity", "$3900000.00"},
{"Lowest Capacity Asset", "ES 1S1"},
{"Fitness Score", "0.007"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "0.484"},
{"Return Over Maximum Drawdown", "1.736"},
{"Portfolio Turnover", "0.011"},
{"Sortino Ratio", "0.563"},
{"Return Over Maximum Drawdown", "1.87"},
{"Portfolio Turnover", "0.01"},
{"Total Insights Generated", "0"},
{"Total Insights Closed", "0"},
{"Total Insights Analysis Completed", "0"},
@@ -178,7 +178,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Mean Population Magnitude", "0%"},
{"Rolling Averaged Population Direction", "0%"},
{"Rolling Averaged Population Magnitude", "0%"},
{"OrderListHash", "7d6fb409115f2f8d403c7eb261b9b3b6"}
{"OrderListHash", "8aa2ed1319e8bb5beb403476a5aebfef"}
};
}
}

View File

@@ -92,7 +92,7 @@ namespace QuantConnect.Algorithm.CSharp
}
}
if (_lastDateLog.Month != Time.Month)
if (_lastDateLog.Month != Time.Month && _continuousContract.HasData)
{
_lastDateLog = Time;
@@ -101,7 +101,7 @@ namespace QuantConnect.Algorithm.CSharp
{
Liquidate();
}
else if(_continuousContract.HasData)
else
{
// This works because we set this contract as tradable, even if it's a canonical security
Buy(_continuousContract.Symbol, 1);
@@ -151,14 +151,14 @@ namespace QuantConnect.Algorithm.CSharp
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Trades", "3"},
{"Average Win", "1.11%"},
{"Average Win", "1.16%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "2.092%"},
{"Drawdown", "1.700%"},
{"Compounding Annual Return", "2.229%"},
{"Drawdown", "1.600%"},
{"Expectancy", "0"},
{"Net Profit", "1.055%"},
{"Sharpe Ratio", "0.682"},
{"Probabilistic Sharpe Ratio", "36.937%"},
{"Net Profit", "1.118%"},
{"Sharpe Ratio", "0.726"},
{"Probabilistic Sharpe Ratio", "38.511%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
@@ -166,18 +166,18 @@ namespace QuantConnect.Algorithm.CSharp
{"Beta", "0.099"},
{"Annual Standard Deviation", "0.022"},
{"Annual Variance", "0"},
{"Information Ratio", "-2.742"},
{"Information Ratio", "-2.74"},
{"Tracking Error", "0.076"},
{"Treynor Ratio", "0.149"},
{"Treynor Ratio", "0.159"},
{"Total Fees", "$5.55"},
{"Estimated Strategy Capacity", "$190000.00"},
{"Estimated Strategy Capacity", "$290000.00"},
{"Lowest Capacity Asset", "ES 1S1"},
{"Fitness Score", "0.01"},
{"Fitness Score", "0.009"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "0.479"},
{"Return Over Maximum Drawdown", "1.652"},
{"Portfolio Turnover", "0.015"},
{"Sortino Ratio", "0.498"},
{"Return Over Maximum Drawdown", "1.803"},
{"Portfolio Turnover", "0.014"},
{"Total Insights Generated", "0"},
{"Total Insights Closed", "0"},
{"Total Insights Analysis Completed", "0"},
@@ -191,7 +191,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Mean Population Magnitude", "0%"},
{"Rolling Averaged Population Direction", "0%"},
{"Rolling Averaged Population Magnitude", "0%"},
{"OrderListHash", "9f7574803b8ebfac8f912019c943d27e"}
{"OrderListHash", "e669103cc598f59d85f5e8d5f0b8df30"}
};
}
}

View File

@@ -20,6 +20,7 @@ using QuantConnect.Interfaces;
using QuantConnect.Securities;
using System.Collections.Generic;
using QuantConnect.Securities.Future;
using QuantConnect.Data.UniverseSelection;
namespace QuantConnect.Algorithm.CSharp
{
@@ -90,6 +91,16 @@ namespace QuantConnect.Algorithm.CSharp
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
Debug($"{Time}-{changes}");
if (changes.AddedSecurities.Any(security => security.Symbol != _continuousContract.Symbol)
|| changes.RemovedSecurities.Any(security => security.Symbol != _continuousContract.Symbol))
{
throw new Exception($"We got an unexpected security changes {changes}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>

View File

@@ -22,6 +22,7 @@ using QuantConnect.Securities;
using QuantConnect.Data.Market;
using System.Collections.Generic;
using QuantConnect.Securities.Future;
using QuantConnect.Data.UniverseSelection;
namespace QuantConnect.Algorithm.CSharp
{
@@ -31,8 +32,9 @@ namespace QuantConnect.Algorithm.CSharp
public class ContinuousFutureRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private List<SymbolChangedEvent> _mappings = new();
private Symbol _currentMappedSymbol;
private Future _continuousContract;
private DateTime _lastDateLog;
private DateTime _lastMonth;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
@@ -55,6 +57,17 @@ namespace QuantConnect.Algorithm.CSharp
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice data)
{
// we subtract a minute cause we can get data on the market close, from the previous minute
if (!_continuousContract.Exchange.DateTimeIsOpen(Time.AddMinutes(-1)))
{
if (data.Bars.Count > 0 || data.QuoteBars.Count > 0)
{
throw new Exception($"We are getting data during closed market!");
}
}
var currentlyMappedSecurity = Securities[_continuousContract.Mapped];
if (data.Keys.Count != 1)
{
throw new Exception($"We are getting data for more than one symbols! {string.Join(",", data.Keys.Select(symbol => symbol))}");
@@ -65,7 +78,12 @@ namespace QuantConnect.Algorithm.CSharp
if (changedEvent.Symbol == _continuousContract.Symbol)
{
_mappings.Add(changedEvent);
Log($"SymbolChanged event: {changedEvent}");
Log($"{Time} - SymbolChanged event: {changedEvent}");
if (_currentMappedSymbol == _continuousContract.Mapped)
{
throw new Exception($"Continuous contract current symbol did not change! {_continuousContract.Mapped}");
}
var currentExpiration = changedEvent.Symbol.Underlying.ID.Date;
var frontMonthExpiration = FuturesExpiryFunctions.FuturesExpiryFunction(_continuousContract.Symbol)(Time.AddMonths(1));
@@ -77,20 +95,19 @@ namespace QuantConnect.Algorithm.CSharp
}
}
}
if (_lastDateLog.Month != Time.Month)
if (_lastMonth.Month != Time.Month && currentlyMappedSecurity.HasData)
{
_lastDateLog = Time;
_lastMonth = Time;
Log($"{Time}- {Securities[_continuousContract.Symbol].GetLastData()}");
Log($"{Time}- {currentlyMappedSecurity.GetLastData()}");
if (Portfolio.Invested)
{
Liquidate();
}
else if(_continuousContract.HasData)
else
{
// This works because we set this contract as tradable, even if it's a canonical security
Buy(_continuousContract.Symbol, 1);
Buy(currentlyMappedSecurity.Symbol, 1);
}
if(Time.Month == 1 && Time.Year == 2013)
@@ -102,6 +119,8 @@ namespace QuantConnect.Algorithm.CSharp
}
}
}
_currentMappedSymbol = _continuousContract.Mapped;
}
public override void OnOrderEvent(OrderEvent orderEvent)
@@ -112,6 +131,16 @@ namespace QuantConnect.Algorithm.CSharp
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
Debug($"{Time}-{changes}");
if (changes.AddedSecurities.Any(security => security.Symbol != _continuousContract.Symbol)
|| changes.RemovedSecurities.Any(security => security.Symbol != _continuousContract.Symbol))
{
throw new Exception($"We got an unexpected security changes {changes}");
}
}
public override void OnEndOfAlgorithm()
{
var expectedMappingCounts = 2;
@@ -137,32 +166,32 @@ namespace QuantConnect.Algorithm.CSharp
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Trades", "3"},
{"Average Win", "1.03%"},
{"Average Win", "1.21%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "1.970%"},
{"Drawdown", "1.400%"},
{"Compounding Annual Return", "2.392%"},
{"Drawdown", "1.600%"},
{"Expectancy", "0"},
{"Net Profit", "0.994%"},
{"Sharpe Ratio", "0.7"},
{"Probabilistic Sharpe Ratio", "37.553%"},
{"Net Profit", "1.199%"},
{"Sharpe Ratio", "0.775"},
{"Probabilistic Sharpe Ratio", "40.287%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.006"},
{"Beta", "0.091"},
{"Annual Standard Deviation", "0.02"},
{"Beta", "0.099"},
{"Annual Standard Deviation", "0.022"},
{"Annual Variance", "0"},
{"Information Ratio", "-2.745"},
{"Information Ratio", "-2.726"},
{"Tracking Error", "0.076"},
{"Treynor Ratio", "0.153"},
{"Treynor Ratio", "0.169"},
{"Total Fees", "$5.55"},
{"Estimated Strategy Capacity", "$48000000.00"},
{"Lowest Capacity Asset", "ES 1S1"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Fitness Score", "0.01"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "0.492"},
{"Return Over Maximum Drawdown", "1.708"},
{"Sortino Ratio", "0.516"},
{"Return Over Maximum Drawdown", "1.935"},
{"Portfolio Turnover", "0.016"},
{"Total Insights Generated", "0"},
{"Total Insights Closed", "0"},
@@ -177,7 +206,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Mean Population Magnitude", "0%"},
{"Rolling Averaged Population Direction", "0%"},
{"Rolling Averaged Population Magnitude", "0%"},
{"OrderListHash", "fb3bb82d84fc6c390a40f36d0d1faf59"}
{"OrderListHash", "8ad040c62ad255e4f9cd423364147e85"}
};
}
}

View File

@@ -97,7 +97,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Average Win", "1.64%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "7.329%"},
{"Drawdown", "1.500%"},
{"Drawdown", "1.300%"},
{"Expectancy", "0"},
{"Net Profit", "1.642%"},
{"Sharpe Ratio", "2.36"},

View File

@@ -109,7 +109,6 @@ namespace QuantConnect.Algorithm.Framework
/// <summary>
/// Invokes the provided <paramref name="add"/> and <paramref name="remove"/> functions for each
/// <seealso cref="SecurityChanges.Added"/> and <seealso cref="SecurityChanges.Removed"/>, respectively
/// </summary>
/// <param name="changes">The security changes to process</param>
/// <param name="add">Function called for each added security</param>
@@ -126,4 +125,4 @@ namespace QuantConnect.Algorithm.Framework
}
}
}
}
}

View File

@@ -0,0 +1,66 @@
# 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.
from AlgorithmImports import *
### <summary>
### Basic Continuous Futures Template Algorithm
### </summary>
class BasicTemplateContinuousFutureAlgorithm(QCAlgorithm):
'''Basic template algorithm simply initializes the date range and cash'''
def Initialize(self):
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
self.SetStartDate(2013, 7, 1)
self.SetEndDate(2014, 1, 1)
self._continuousContract = self.AddFuture(Futures.Indices.SP500EMini,
dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
dataMappingMode = DataMappingMode.LastTradingDay,
contractDepthOffset= 0)
self._fast = self.SMA(self._continuousContract.Symbol, 3, Resolution.Daily)
self._slow = self.SMA(self._continuousContract.Symbol, 10, Resolution.Daily)
self._currentContract = None
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Arguments:
data: Slice object keyed by symbol containing the stock data
'''
for changedEvent in data.SymbolChangedEvents.Values:
if changedEvent.Symbol == self._continuousContract.Symbol:
self.Log(f"SymbolChanged event: {changedEvent}")
if not self.Portfolio.Invested:
if self._fast.Current.Value > self._slow.Current.Value:
self._currentContract = self.Securities[self._continuousContract.Mapped]
self.Buy(self._currentContract.Symbol, 1)
elif self._fast.Current.Value < self._slow.Current.Value:
self.Liquidate()
if self._currentContract is not None and self._currentContract.Symbol != self._continuousContract.Mapped:
self.Log(f"{Time} - rolling position from {self._currentContract.Symbol} to {self._continuousContract.Mapped}")
currentPositionSize = self._currentContract.Holdings.Quantity
self.Liquidate(self._currentContract.Symbol)
self.Buy(self._continuousContract.Mapped, currentPositionSize)
self._currentContract = self.Securities[self._continuousContract.Mapped]
def OnOrderEvent(self, orderEvent):
self.Debug("Purchased Stock: {0}".format(orderEvent.Symbol))
def OnSecuritiesChanged(self, changes):
self.Debug(f"{self.Time}-{changes}")

View File

@@ -31,6 +31,7 @@ class ContinuousFutureRegressionAlgorithm(QCAlgorithm):
dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
dataMappingMode = DataMappingMode.LastTradingDay,
contractDepthOffset= 0)
self._currentMappedSymbol = self._continuousContract.Symbol;
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
@@ -38,6 +39,7 @@ class ContinuousFutureRegressionAlgorithm(QCAlgorithm):
Arguments:
data: Slice object keyed by symbol containing the stock data
'''
currentlyMappedSecurity = self.Securities[self._continuousContract.Mapped]
if len(data.Keys) != 1:
raise ValueError(f"We are getting data for more than one symbols! {','.join(data.Keys)}")
@@ -46,25 +48,33 @@ class ContinuousFutureRegressionAlgorithm(QCAlgorithm):
self._mappings.append(changedEvent)
self.Log(f"SymbolChanged event: {changedEvent}")
if self._lastDateLog != self.Time.month:
if self._currentMappedSymbol == self._continuousContract.Mapped:
raise ValueError(f"Continuous contract current symbol did not change! {self._continuousContract.Mapped}")
if self._lastDateLog != self.Time.month and currentlyMappedSecurity.HasData:
self._lastDateLog = self.Time.month
self.Log(f"{self.Time}- {self._continuousContract.GetLastData()}")
self.Log(f"{self.Time}- {currentlyMappedSecurity.GetLastData()}")
if self.Portfolio.Invested:
self.Liquidate()
elif self._continuousContract.HasData:
else:
# This works because we set this contract as tradable, even if it's a canonical security
self.Buy(self._continuousContract.Symbol, 1)
self.Buy(currentlyMappedSecurity.Symbol, 1)
if self.Time.month == 1 and self.Time.year == 2013:
response = self.History( [ self._continuousContract.Symbol ], 60 * 24 * 90)
if response.empty:
raise ValueError("Unexpected empty history response")
self._currentMappedSymbol = self._continuousContract.Mapped
def OnOrderEvent(self, orderEvent):
if orderEvent.Status == OrderStatus.Filled:
self.Debug("Purchased Stock: {0}".format(orderEvent.Symbol))
def OnSecuritiesChanged(self, changes):
self.Debug(f"{self.Time}-{changes}")
def OnEndOfAlgorithm(self):
expectedMappingCounts = 2
if len(self._mappings) != expectedMappingCounts:

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -28,6 +28,7 @@ namespace QuantConnect.Algorithm
/// Sets the alpha model
/// </summary>
/// <param name="alpha">Model that generates alpha</param>
[DocumentationAttribute(AlgorithmFramework)]
public void SetAlpha(PyObject alpha)
{
IAlphaModel model;
@@ -45,6 +46,7 @@ namespace QuantConnect.Algorithm
/// Adds a new alpha model
/// </summary>
/// <param name="alpha">Model that generates alpha to add</param>
[DocumentationAttribute(AlgorithmFramework)]
public void AddAlpha(PyObject alpha)
{
IAlphaModel model;
@@ -62,6 +64,8 @@ namespace QuantConnect.Algorithm
/// Sets the execution model
/// </summary>
/// <param name="execution">Model defining how to execute trades to reach a portfolio target</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(TradingAndOrders)]
public void SetExecution(PyObject execution)
{
IExecutionModel model;
@@ -79,6 +83,8 @@ namespace QuantConnect.Algorithm
/// Sets the portfolio construction model
/// </summary>
/// <param name="portfolioConstruction">Model defining how to build a portfolio from alphas</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(TradingAndOrders)]
public void SetPortfolioConstruction(PyObject portfolioConstruction)
{
IPortfolioConstructionModel model;
@@ -96,6 +102,8 @@ namespace QuantConnect.Algorithm
/// Sets the universe selection model
/// </summary>
/// <param name="universeSelection">Model defining universes for the algorithm</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(Universes)]
public void SetUniverseSelection(PyObject universeSelection)
{
IUniverseSelectionModel model;
@@ -110,6 +118,8 @@ namespace QuantConnect.Algorithm
/// Adds a new universe selection model
/// </summary>
/// <param name="universeSelection">Model defining universes for the algorithm to add</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(Universes)]
public void AddUniverseSelection(PyObject universeSelection)
{
IUniverseSelectionModel model;
@@ -124,6 +134,8 @@ namespace QuantConnect.Algorithm
/// Sets the risk management model
/// </summary>
/// <param name="riskManagement">Model defining how risk is managed</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(TradingAndOrders)]
public void SetRiskManagement(PyObject riskManagement)
{
IRiskManagementModel model;
@@ -141,6 +153,8 @@ namespace QuantConnect.Algorithm
/// Adds a new risk management model
/// </summary>
/// <param name="riskManagement">Model defining how risk is managed to add</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(TradingAndOrders)]
public void AddRiskManagement(PyObject riskManagement)
{
IRiskManagementModel model;
@@ -151,4 +165,4 @@ namespace QuantConnect.Algorithm
AddRiskManagement(model);
}
}
}
}

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -38,37 +38,44 @@ namespace QuantConnect.Algorithm
/// Enables additional logging of framework models including:
/// All insights, portfolio targets, order events, and any risk management altered targets
/// </summary>
[DocumentationAttribute(Logging)]
public bool DebugMode { get; set; }
/// <summary>
/// Gets or sets the universe selection model.
/// </summary>
[DocumentationAttribute(AlgorithmFramework)]
public IUniverseSelectionModel UniverseSelection { get; set; }
/// <summary>
/// Gets or sets the alpha model
/// </summary>
[DocumentationAttribute(AlgorithmFramework)]
public IAlphaModel Alpha { get; set; }
/// <summary>
/// Gets or sets the portfolio construction model
/// </summary>
[DocumentationAttribute(AlgorithmFramework)]
public IPortfolioConstructionModel PortfolioConstruction { get; set; }
/// <summary>
/// Gets or sets the execution model
/// </summary>
[DocumentationAttribute(AlgorithmFramework)]
public IExecutionModel Execution { get; set; }
/// <summary>
/// Gets or sets the risk management model
/// </summary>
[DocumentationAttribute(AlgorithmFramework)]
public IRiskManagementModel RiskManagement { get; set; }
/// <summary>
/// Called by setup handlers after Initialize and allows the algorithm a chance to organize
/// the data gather in the Initialize method
/// </summary>
[DocumentationAttribute(AlgorithmFramework)]
public void FrameworkPostInitialize()
{
//Prevents execution in the case of cash brokerage with IExecutionModel and IPortfolioConstructionModel
@@ -97,6 +104,8 @@ namespace QuantConnect.Algorithm
/// Used to send data updates to algorithm framework models
/// </summary>
/// <param name="slice">The current data slice</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(HandlingData)]
public void OnFrameworkData(Slice slice)
{
if (UtcTime >= UniverseSelection.GetNextRefreshTimeUtc())
@@ -170,6 +179,7 @@ namespace QuantConnect.Algorithm
/// and the <see cref="IExecutionModel"/> will execute the <see cref="IPortfolioTarget"/>
/// </summary>
/// <param name="insights">The insight to process</param>
[DocumentationAttribute(AlgorithmFramework)]
private void ProcessInsights(Insight[] insights)
{
// construct portfolio targets from insights
@@ -244,6 +254,8 @@ namespace QuantConnect.Algorithm
/// Used to send security changes to algorithm framework models
/// </summary>
/// <param name="changes">Security additions/removals for this time step</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(Universes)]
public void OnFrameworkSecuritiesChanged(SecurityChanges changes)
{
if (DebugMode)
@@ -261,6 +273,8 @@ namespace QuantConnect.Algorithm
/// Sets the universe selection model
/// </summary>
/// <param name="universeSelection">Model defining universes for the algorithm</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(Universes)]
public void SetUniverseSelection(IUniverseSelectionModel universeSelection)
{
UniverseSelection = universeSelection;
@@ -270,6 +284,8 @@ namespace QuantConnect.Algorithm
/// Adds a new universe selection model
/// </summary>
/// <param name="universeSelection">Model defining universes for the algorithm to add</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(Universes)]
public void AddUniverseSelection(IUniverseSelectionModel universeSelection)
{
if (UniverseSelection.GetType() != typeof(NullUniverseSelectionModel))
@@ -294,6 +310,7 @@ namespace QuantConnect.Algorithm
/// Sets the alpha model
/// </summary>
/// <param name="alpha">Model that generates alpha</param>
[DocumentationAttribute(AlgorithmFramework)]
public void SetAlpha(IAlphaModel alpha)
{
Alpha = alpha;
@@ -303,6 +320,7 @@ namespace QuantConnect.Algorithm
/// Adds a new alpha model
/// </summary>
/// <param name="alpha">Model that generates alpha to add</param>
[DocumentationAttribute(AlgorithmFramework)]
public void AddAlpha(IAlphaModel alpha)
{
if (Alpha.GetType() != typeof(NullAlphaModel))
@@ -327,6 +345,8 @@ namespace QuantConnect.Algorithm
/// Sets the portfolio construction model
/// </summary>
/// <param name="portfolioConstruction">Model defining how to build a portfolio from insights</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(TradingAndOrders)]
public void SetPortfolioConstruction(IPortfolioConstructionModel portfolioConstruction)
{
PortfolioConstruction = portfolioConstruction;
@@ -336,6 +356,8 @@ namespace QuantConnect.Algorithm
/// Sets the execution model
/// </summary>
/// <param name="execution">Model defining how to execute trades to reach a portfolio target</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(TradingAndOrders)]
public void SetExecution(IExecutionModel execution)
{
Execution = execution;
@@ -345,6 +367,8 @@ namespace QuantConnect.Algorithm
/// Sets the risk management model
/// </summary>
/// <param name="riskManagement">Model defining how risk is managed</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(TradingAndOrders)]
public void SetRiskManagement(IRiskManagementModel riskManagement)
{
RiskManagement = riskManagement;
@@ -354,6 +378,8 @@ namespace QuantConnect.Algorithm
/// Adds a new risk management model
/// </summary>
/// <param name="riskManagement">Model defining how risk is managed to add</param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(TradingAndOrders)]
public void AddRiskManagement(IRiskManagementModel riskManagement)
{
if (RiskManagement.GetType() != typeof(NullRiskManagementModel))
@@ -380,6 +406,7 @@ namespace QuantConnect.Algorithm
/// QCAlgorithm that have been ported into the algorithm framework.
/// </summary>
/// <param name="insights">The array of insights to be emitted</param>
[DocumentationAttribute(AlgorithmFramework)]
public void EmitInsights(params Insight[] insights)
{
if (IsWarmingUp)
@@ -403,6 +430,7 @@ namespace QuantConnect.Algorithm
/// QCAlgorithm that have been ported into the algorithm framework.
/// </summary>
/// <param name="insight">The insight to be emitted</param>
[DocumentationAttribute(AlgorithmFramework)]
public void EmitInsights(Insight insight)
{
EmitInsights(new[] { insight });

View File

@@ -39,6 +39,7 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Gets whether or not this algorithm is still warming up
/// </summary>
[DocumentationAttribute(HistoricalData)]
public bool IsWarmingUp
{
get;
@@ -49,6 +50,7 @@ namespace QuantConnect.Algorithm
/// Sets the warm up period to the specified value
/// </summary>
/// <param name="timeSpan">The amount of time to warm up, this does not take into account market hours/weekends</param>
[DocumentationAttribute(HistoricalData)]
public void SetWarmup(TimeSpan timeSpan)
{
SetWarmUp(timeSpan, null);
@@ -58,6 +60,7 @@ namespace QuantConnect.Algorithm
/// Sets the warm up period to the specified value
/// </summary>
/// <param name="timeSpan">The amount of time to warm up, this does not take into account market hours/weekends</param>
[DocumentationAttribute(HistoricalData)]
public void SetWarmUp(TimeSpan timeSpan)
{
SetWarmup(timeSpan);
@@ -68,6 +71,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="timeSpan">The amount of time to warm up, this does not take into account market hours/weekends</param>
/// <param name="resolution">The resolution to request</param>
[DocumentationAttribute(HistoricalData)]
public void SetWarmup(TimeSpan timeSpan, Resolution? resolution)
{
if (_locked)
@@ -85,6 +89,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="timeSpan">The amount of time to warm up, this does not take into account market hours/weekends</param>
/// <param name="resolution">The resolution to request</param>
[DocumentationAttribute(HistoricalData)]
public void SetWarmUp(TimeSpan timeSpan, Resolution? resolution)
{
SetWarmup(timeSpan, resolution);
@@ -97,6 +102,7 @@ namespace QuantConnect.Algorithm
/// use 200 minute bars.
/// </summary>
/// <param name="barCount">The number of data points requested for warm up</param>
[DocumentationAttribute(HistoricalData)]
public void SetWarmup(int barCount)
{
SetWarmUp(barCount, null);
@@ -109,6 +115,7 @@ namespace QuantConnect.Algorithm
/// use 200 minute bars.
/// </summary>
/// <param name="barCount">The number of data points requested for warm up</param>
[DocumentationAttribute(HistoricalData)]
public void SetWarmUp(int barCount)
{
SetWarmup(barCount);
@@ -120,6 +127,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="barCount">The number of data points requested for warm up</param>
/// <param name="resolution">The resolution to request</param>
[DocumentationAttribute(HistoricalData)]
public void SetWarmup(int barCount, Resolution? resolution)
{
if (_locked)
@@ -138,6 +146,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="barCount">The number of data points requested for warm up</param>
/// <param name="resolution">The resolution to request</param>
[DocumentationAttribute(HistoricalData)]
public void SetWarmUp(int barCount, Resolution? resolution)
{
SetWarmup(barCount, resolution);
@@ -146,6 +155,7 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Sets <see cref="IAlgorithm.IsWarmingUp"/> to false to indicate this algorithm has finished its warm up
/// </summary>
[DocumentationAttribute(HistoricalData)]
public void SetFinishedWarmingUp()
{
IsWarmingUp = false;
@@ -165,6 +175,7 @@ namespace QuantConnect.Algorithm
/// Gets the history requests required for provide warm up data for the algorithm
/// </summary>
/// <returns></returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<HistoryRequest> GetWarmupHistoryRequests()
{
if (_warmupBarCount.HasValue)
@@ -189,6 +200,7 @@ namespace QuantConnect.Algorithm
/// <param name="span">The span over which to request data. This is a calendar span, so take into consideration weekends and such</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing data over the most recent span for all configured securities</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<Slice> History(TimeSpan span, Resolution? resolution = null)
{
return History(Securities.Keys, Time - span, Time, resolution).Memoize();
@@ -202,6 +214,7 @@ namespace QuantConnect.Algorithm
/// <param name="periods">The number of bars to request</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing data over the most recent span for all configured securities</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<Slice> History(int periods, Resolution? resolution = null)
{
return History(Securities.Keys, periods, resolution).Memoize();
@@ -215,6 +228,7 @@ namespace QuantConnect.Algorithm
/// <param name="span">The span over which to retrieve recent historical data</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<DataDictionary<T>> History<T>(TimeSpan span, Resolution? resolution = null)
where T : IBaseData
{
@@ -230,6 +244,7 @@ namespace QuantConnect.Algorithm
/// <param name="span">The span over which to retrieve recent historical data</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<DataDictionary<T>> History<T>(IEnumerable<Symbol> symbols, TimeSpan span, Resolution? resolution = null)
where T : IBaseData
{
@@ -246,6 +261,7 @@ namespace QuantConnect.Algorithm
/// <param name="periods">The number of bars to request</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<DataDictionary<T>> History<T>(IEnumerable<Symbol> symbols, int periods, Resolution? resolution = null)
where T : IBaseData
{
@@ -272,6 +288,7 @@ namespace QuantConnect.Algorithm
/// <param name="end">The end time in the algorithm's time zone</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<DataDictionary<T>> History<T>(IEnumerable<Symbol> symbols, DateTime start, DateTime end, Resolution? resolution = null)
where T : IBaseData
{
@@ -294,6 +311,7 @@ namespace QuantConnect.Algorithm
/// <param name="span">The span over which to retrieve recent historical data</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<T> History<T>(Symbol symbol, TimeSpan span, Resolution? resolution = null)
where T : IBaseData
{
@@ -308,6 +326,7 @@ namespace QuantConnect.Algorithm
/// <param name="periods">The number of bars to request</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<TradeBar> History(Symbol symbol, int periods, Resolution? resolution = null)
{
if (symbol == null) throw new ArgumentException(_symbolEmptyErrorMessage);
@@ -328,6 +347,7 @@ namespace QuantConnect.Algorithm
/// <param name="periods">The number of bars to request</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<T> History<T>(Symbol symbol, int periods, Resolution? resolution = null)
where T : IBaseData
{
@@ -347,6 +367,7 @@ namespace QuantConnect.Algorithm
/// <param name="end">The end time in the algorithm's time zone</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<T> History<T>(Symbol symbol, DateTime start, DateTime end, Resolution? resolution = null)
where T : IBaseData
{
@@ -363,6 +384,7 @@ namespace QuantConnect.Algorithm
/// <param name="span">The span over which to retrieve recent historical data</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<TradeBar> History(Symbol symbol, TimeSpan span, Resolution? resolution = null)
{
return History(symbol, Time - span, Time, resolution);
@@ -376,6 +398,7 @@ namespace QuantConnect.Algorithm
/// <param name="end">The end time in the algorithm's time zone</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<TradeBar> History(Symbol symbol, DateTime start, DateTime end, Resolution? resolution = null)
{
var securityType = symbol.ID.SecurityType;
@@ -403,6 +426,7 @@ namespace QuantConnect.Algorithm
/// <param name="span">The span over which to retrieve recent historical data</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<Slice> History(IEnumerable<Symbol> symbols, TimeSpan span, Resolution? resolution = null)
{
return History(symbols, Time - span, Time, resolution).Memoize();
@@ -417,6 +441,7 @@ namespace QuantConnect.Algorithm
/// <param name="periods">The number of bars to request</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<Slice> History(IEnumerable<Symbol> symbols, int periods, Resolution? resolution = null)
{
if (resolution == Resolution.Tick) throw new ArgumentException("History functions that accept a 'periods' parameter can not be used with Resolution.Tick");
@@ -433,6 +458,7 @@ namespace QuantConnect.Algorithm
/// <param name="fillForward">True to fill forward missing data, false otherwise</param>
/// <param name="extendedMarket">True to include extended market hours data, false otherwise</param>
/// <returns>An enumerable of slice containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<Slice> History(IEnumerable<Symbol> symbols, DateTime start, DateTime end, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarket = null)
{
return History(CreateDateRangeHistoryRequests(symbols, start, end, resolution, fillForward, extendedMarket)).Memoize();
@@ -443,6 +469,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="request">the history request to execute</param>
/// <returns>An enumerable of slice satisfying the specified history request</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<Slice> History(HistoryRequest request)
{
return History(new[] { request }).Memoize();
@@ -453,6 +480,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="requests">the history requests to execute</param>
/// <returns>An enumerable of slice satisfying the specified history request</returns>
[DocumentationAttribute(HistoricalData)]
public IEnumerable<Slice> History(IEnumerable<HistoryRequest> requests)
{
return History(requests, TimeZone).Memoize();
@@ -463,6 +491,8 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="security"><see cref="Security"/> object for which to retrieve historical data</param>
/// <returns>Securities historical data</returns>
[DocumentationAttribute(AddingData)]
[DocumentationAttribute(HistoricalData)]
public IEnumerable<BaseData> GetLastKnownPrices(Security security)
{
return GetLastKnownPrices(security.Symbol);
@@ -473,6 +503,8 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="symbol">The symbol we want to get seed data for</param>
/// <returns>Securities historical data</returns>
[DocumentationAttribute(AddingData)]
[DocumentationAttribute(HistoricalData)]
public IEnumerable<BaseData> GetLastKnownPrices(Symbol symbol)
{
if (!HistoryRequestValid(symbol) || HistoryProvider == null)
@@ -534,6 +566,8 @@ namespace QuantConnect.Algorithm
/// <returns>A single <see cref="BaseData"/> object with the last known price</returns>
[Obsolete("This method is obsolete please use 'GetLastKnownPrices' which will return the last data point" +
" for each type associated with the requested security")]
[DocumentationAttribute(AddingData)]
[DocumentationAttribute(HistoricalData)]
public BaseData GetLastKnownPrice(Security security)
{
return GetLastKnownPrices(security.Symbol)
@@ -563,7 +597,8 @@ namespace QuantConnect.Algorithm
}
return config;
}
[DocumentationAttribute(HistoricalData)]
private IEnumerable<Slice> History(IEnumerable<HistoryRequest> requests, DateTimeZone timeZone)
{
var sentMessage = false;

View File

@@ -30,6 +30,7 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Gets whether or not WarmUpIndicator is allowed to warm up indicators/>
/// </summary>
[DocumentationAttribute(Indicators)]
public bool EnableAutomaticIndicatorWarmUp { get; set; } = false;
/// <summary>
@@ -42,6 +43,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar.</param>
/// <returns></returns>
[DocumentationAttribute(Indicators)]
public AccelerationBands ABANDS(Symbol symbol, int period, decimal width = 4, MovingAverageType movingAverageType = MovingAverageType.Simple,
Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
@@ -64,6 +66,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The AccumulationDistribution indicator for the requested symbol over the speified period</returns>
[DocumentationAttribute(Indicators)]
public AccumulationDistribution AD(Symbol symbol, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, "AD", resolution);
@@ -87,6 +90,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The AccumulationDistributionOscillator indicator for the requested symbol over the speified period</returns>
[DocumentationAttribute(Indicators)]
public AccumulationDistributionOscillator ADOSC(Symbol symbol, int fastPeriod, int slowPeriod, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"ADOSC({fastPeriod},{slowPeriod})", resolution);
@@ -111,6 +115,7 @@ namespace QuantConnect.Algorithm
/// <param name="period">Size of the rolling series to fit onto</param>
/// <param name="resolution">The resolution</param>
/// <returns>The ARIMA indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public AutoRegressiveIntegratedMovingAverage ARIMA(Symbol symbol, int arOrder, int diffOrder, int maOrder, int period, Resolution? resolution = null)
{
var name = CreateIndicatorName(symbol, $"ARIMA({arOrder},{diffOrder},{maOrder},{period})", resolution);
@@ -134,6 +139,7 @@ namespace QuantConnect.Algorithm
/// <param name="period">The period over which to compute the Average Directional Index</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The Average Directional Index indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public AverageDirectionalIndex ADX(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"ADX({period})", resolution);
@@ -157,6 +163,7 @@ namespace QuantConnect.Algorithm
/// <param name="slowPeriod">The period of the slow moving average associated with the AO</param>
/// <param name="type">The type of moving average used when computing the fast and slow term. Defaults to simple moving average.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
[DocumentationAttribute(Indicators)]
public AwesomeOscillator AO(Symbol symbol, int slowPeriod, int fastPeriod, MovingAverageType type, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"AO({fastPeriod},{slowPeriod},{type})", resolution);
@@ -179,6 +186,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The AverageDirectionalMovementIndexRating indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public AverageDirectionalMovementIndexRating ADXR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"ADXR({period})", resolution);
@@ -207,6 +215,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The ArnaudLegouxMovingAverage indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public ArnaudLegouxMovingAverage ALMA(Symbol symbol, int period, int sigma = 6, decimal offset = 0.85m, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"ALMA({period},{sigma},{offset})", resolution);
@@ -231,6 +240,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The AbsolutePriceOscillator indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public AbsolutePriceOscillator APO(Symbol symbol, int fastPeriod, int slowPeriod, MovingAverageType movingAverageType, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"APO({fastPeriod},{slowPeriod})", resolution);
@@ -253,6 +263,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>An AroonOscillator configured with the specied periods</returns>
[DocumentationAttribute(Indicators)]
public AroonOscillator AROON(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
return AROON(symbol, period, period, resolution, selector);
@@ -267,6 +278,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>An AroonOscillator configured with the specified periods</returns>
[DocumentationAttribute(Indicators)]
public AroonOscillator AROON(Symbol symbol, int upPeriod, int downPeriod, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"AROON({upPeriod},{downPeriod})", resolution);
@@ -291,6 +303,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>A new AverageTrueRange indicator with the specified smoothing type and period</returns>
[DocumentationAttribute(Indicators)]
public AverageTrueRange ATR(Symbol symbol, int period, MovingAverageType type = MovingAverageType.Simple, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"ATR({period})", resolution);
@@ -314,6 +327,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The AugenPriceSpike indicator for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public AugenPriceSpike APS(Symbol symbol, int period = 3, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"APS({period})", resolution);
@@ -338,6 +352,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>A BollingerBands configured with the specified period</returns>
[DocumentationAttribute(Indicators)]
public BollingerBands BB(Symbol symbol, int period, decimal k, MovingAverageType movingAverageType = MovingAverageType.Simple, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"BB({period},{k})", resolution);
@@ -361,6 +376,7 @@ namespace QuantConnect.Algorithm
/// <param name="period">The period of the Beta indicator</param>
/// <param name="resolution">The resolution</param>
/// <returns>The Beta indicator for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public Beta B(Symbol target, Symbol reference, int period, Resolution? resolution = null)
{
var name = CreateIndicatorName(QuantConnect.Symbol.None, "B", resolution);
@@ -385,6 +401,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The Balance Of Power indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public BalanceOfPower BOP(Symbol symbol, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, "BOP", resolution);
@@ -409,6 +426,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The Coppock Curve indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public CoppockCurve CC(Symbol symbol, int shortRocPeriod = 11, int longRocPeriod = 14, int lwmaPeriod = 10, Resolution? resolution = null,
Func<IBaseData, decimal> selector = null)
{
@@ -434,6 +452,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The CommodityChannelIndex indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public CommodityChannelIndex CCI(Symbol symbol, int period, MovingAverageType movingAverageType = MovingAverageType.Simple, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"CCI({period})", resolution);
@@ -456,6 +475,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The ChaikinMoneyFlow indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public ChaikinMoneyFlow CMF(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"CMF({period})", resolution);
@@ -478,6 +498,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The ChandeMomentumOscillator indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public ChandeMomentumOscillator CMO(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"CMO({period})", resolution);
@@ -502,6 +523,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The DeMarker indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public DeMarkerIndicator DEM(Symbol symbol, int period, MovingAverageType type, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"DEM({period},{type})", resolution);
@@ -526,6 +548,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The Donchian Channel indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public DonchianChannel DCH(Symbol symbol, int upperPeriod, int lowerPeriod, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"DCH({upperPeriod},{lowerPeriod})", resolution);
@@ -549,6 +572,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The Donchian Channel indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public DonchianChannel DCH(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
return DCH(symbol, period, period, resolution, selector);
@@ -562,6 +586,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The DoubleExponentialMovingAverage indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public DoubleExponentialMovingAverage DEMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"DEMA({period})", resolution);
@@ -584,6 +609,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>A new registered DetrendedPriceOscillator indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public DetrendedPriceOscillator DPO(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"DPO({period})", resolution);
@@ -607,6 +633,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The ExponentialMovingAverage for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public ExponentialMovingAverage EMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
return EMA(symbol, period, ExponentialMovingAverage.SmoothingFactorDefault(period), resolution, selector);
@@ -622,6 +649,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The ExponentialMovingAverage for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public ExponentialMovingAverage EMA(Symbol symbol, int period, decimal smoothingFactor, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"EMA({period})", resolution);
@@ -646,6 +674,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The EaseOfMovementValue indicator for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public EaseOfMovementValue EMV(Symbol symbol, int period = 1, int scale = 10000, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"EMV({period}, {scale})", resolution);
@@ -669,6 +698,7 @@ namespace QuantConnect.Algorithm
/// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param>
/// <param name="fieldName">The name of the field being selected</param>
/// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns>
[DocumentationAttribute(Indicators)]
public FilteredIdentity FilteredIdentity(Symbol symbol, Func<IBaseData, IBaseDataBar> selector = null, Func<IBaseData, bool> filter = null, string fieldName = null)
{
var resolution = GetSubscription(symbol).Resolution;
@@ -685,6 +715,7 @@ namespace QuantConnect.Algorithm
/// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param>
/// <param name="fieldName">The name of the field being selected</param>
/// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns>
[DocumentationAttribute(Indicators)]
public FilteredIdentity FilteredIdentity(Symbol symbol, Resolution resolution, Func<IBaseData, IBaseDataBar> selector = null, Func<IBaseData, bool> filter = null, string fieldName = null)
{
var name = CreateIndicatorName(symbol, fieldName ?? "close", resolution);
@@ -703,6 +734,7 @@ namespace QuantConnect.Algorithm
/// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param>
/// <param name="fieldName">The name of the field being selected</param>
/// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns>
[DocumentationAttribute(Indicators)]
public FilteredIdentity FilteredIdentity(Symbol symbol, TimeSpan resolution, Func<IBaseData, IBaseDataBar> selector = null, Func<IBaseData, bool> filter = null, string fieldName = null)
{
var name = Invariant($"{symbol}({fieldName ?? "close"}_{resolution})");
@@ -720,6 +752,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The FisherTransform for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public FisherTransform FISH(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"FISH({period})", resolution);
@@ -744,6 +777,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The FRAMA for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public FractalAdaptiveMovingAverage FRAMA(Symbol symbol, int period, int longPeriod = 198, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"FRAMA({period},{longPeriod})", resolution);
@@ -765,6 +799,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The Heikin-Ashi indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public HeikinAshi HeikinAshi(Symbol symbol, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, "HA", resolution);
@@ -787,6 +822,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns></returns>
[DocumentationAttribute(Indicators)]
public HullMovingAverage HMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"HMA({period})", resolution);
@@ -814,6 +850,7 @@ namespace QuantConnect.Algorithm
/// <param name="senkouBDelayPeriod">The period to calculate the Tenkan-sen period</param>
/// <param name="resolution">The resolution</param>
/// <returns>A new IchimokuKinkoHyo indicator with the specified periods and delays</returns>
[DocumentationAttribute(Indicators)]
public IchimokuKinkoHyo ICHIMOKU(Symbol symbol, int tenkanPeriod, int kijunPeriod, int senkouAPeriod, int senkouBPeriod, int senkouADelayPeriod, int senkouBDelayPeriod, Resolution? resolution = null)
{
var name = CreateIndicatorName(symbol, $"ICHIMOKU({tenkanPeriod},{kijunPeriod},{senkouAPeriod},{senkouBPeriod},{senkouADelayPeriod},{senkouBDelayPeriod})", resolution);
@@ -836,6 +873,7 @@ namespace QuantConnect.Algorithm
/// <param name="selector">Selects a value from the BaseData, if null defaults to the .Value property (x => x.Value)</param>
/// <param name="fieldName">The name of the field being selected</param>
/// <returns>A new Identity indicator for the specified symbol and selector</returns>
[DocumentationAttribute(Indicators)]
public Identity Identity(Symbol symbol, Func<IBaseData, decimal> selector = null, string fieldName = null)
{
var resolution = GetSubscription(symbol).Resolution;
@@ -851,6 +889,7 @@ namespace QuantConnect.Algorithm
/// <param name="selector">Selects a value from the BaseData, if null defaults to the .Value property (x => x.Value)</param>
/// <param name="fieldName">The name of the field being selected</param>
/// <returns>A new Identity indicator for the specified symbol and selector</returns>
[DocumentationAttribute(Indicators)]
public Identity Identity(Symbol symbol, Resolution resolution, Func<IBaseData, decimal> selector = null, string fieldName = null)
{
var name = CreateIndicatorName(symbol, fieldName ?? "close", resolution);
@@ -868,6 +907,7 @@ namespace QuantConnect.Algorithm
/// <param name="selector">Selects a value from the BaseData, if null defaults to the .Value property (x => x.Value)</param>
/// <param name="fieldName">The name of the field being selected</param>
/// <returns>A new Identity indicator for the specified symbol and selector</returns>
[DocumentationAttribute(Indicators)]
public Identity Identity(Symbol symbol, TimeSpan resolution, Func<IBaseData, decimal> selector = null, string fieldName = null)
{
var name = Invariant($"{symbol}({fieldName ?? "close"},{resolution})");
@@ -884,6 +924,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The KaufmanAdaptiveMovingAverage indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public KaufmanAdaptiveMovingAverage KAMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
return KAMA(symbol, period, 2, 30, resolution, selector);
@@ -899,6 +940,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The KaufmanAdaptiveMovingAverage indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public KaufmanAdaptiveMovingAverage KAMA(Symbol symbol, int period, int fastEmaPeriod, int slowEmaPeriod, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"KAMA({period},{fastEmaPeriod},{slowEmaPeriod})", resolution);
@@ -913,6 +955,28 @@ namespace QuantConnect.Algorithm
return kaufmanAdaptiveMovingAverage;
}
/// <summary>
/// Creates an KaufmanEfficiencyRatio indicator for the symbol. The indicator will be automatically
/// updated on the given resolution.
/// </summary>
/// <param name="symbol">The symbol whose EF we want</param>
/// <param name="period">The period of the EF</param>
/// <param name="resolution">The resolution</param>
/// <returns>The KaufmanEfficiencyRatio indicator for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public KaufmanEfficiencyRatio KER(Symbol symbol, int period = 2, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"KER({period})", resolution);
var kaufmanEfficiencyRatio = new KaufmanEfficiencyRatio(name, period);
RegisterIndicator(symbol, kaufmanEfficiencyRatio, resolution, selector);
if (EnableAutomaticIndicatorWarmUp)
{
WarmUpIndicator(symbol, kaufmanEfficiencyRatio, resolution);
}
return kaufmanEfficiencyRatio;
}
/// <summary>
/// Creates a new Keltner Channels indicator.
/// The indicator will be automatically updated on the given resolution.
@@ -924,6 +988,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The Keltner Channel indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public KeltnerChannels KCH(Symbol symbol, int period, decimal k, MovingAverageType movingAverageType = MovingAverageType.Simple, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"KCH({period},{k})", resolution);
@@ -946,6 +1011,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar.</param>
/// <returns>log return indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public LogReturn LOGR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"LOGR({period})", resolution);
@@ -968,6 +1034,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar.</param>
/// <returns>A LeastSquaredMovingAverage configured with the specified period</returns>
[DocumentationAttribute(Indicators)]
public LeastSquaresMovingAverage LSMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"LSMA({period})", resolution);
@@ -991,6 +1058,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns></returns>
[DocumentationAttribute(Indicators)]
public LinearWeightedMovingAverage LWMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"LWMA({period})", resolution);
@@ -1016,6 +1084,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The moving average convergence divergence between the fast and slow averages</returns>
[DocumentationAttribute(Indicators)]
public MovingAverageConvergenceDivergence MACD(Symbol symbol, int fastPeriod, int slowPeriod, int signalPeriod, MovingAverageType type = MovingAverageType.Exponential, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"MACD({fastPeriod},{slowPeriod},{signalPeriod})", resolution);
@@ -1038,6 +1107,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The MeanAbsoluteDeviation indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public MeanAbsoluteDeviation MAD(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"MAD({period})", resolution);
@@ -1063,6 +1133,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The Volume Profile indicator for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public VolumeProfile VP(Symbol symbol, int period = 2, decimal valueAreaVolumePercentage = 0.70m, decimal priceRangeRoundOff = 0.05m, Resolution resolution = Resolution.Daily, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"VP({period})", resolution);
@@ -1088,6 +1159,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The Time Profile indicator for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public TimeProfile TP(Symbol symbol, int period = 2, decimal valueAreaVolumePercentage = 0.70m, decimal priceRangeRoundOff = 0.05m, Resolution resolution = Resolution.Daily, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"TP({period})", resolution);
@@ -1111,6 +1183,7 @@ namespace QuantConnect.Algorithm
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null and the symbol is of type TradeBar defaults to the High property,
/// otherwise it defaults to Value property of BaseData (x => x.Value)</param>
/// <returns>A Maximum indicator that compute the max value and the periods since the max value</returns>
[DocumentationAttribute(Indicators)]
public Maximum MAX(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"MAX({period})", resolution);
@@ -1146,6 +1219,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The MoneyFlowIndex indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public MoneyFlowIndex MFI(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"MFI({period})", resolution);
@@ -1170,6 +1244,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The Mass Index indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public MassIndex MASS(Symbol symbol, int emaPeriod = 9, int sumPeriod = 25, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"MASS({emaPeriod},{sumPeriod})", resolution);
@@ -1192,6 +1267,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The MidPoint indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public MidPoint MIDPOINT(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"MIDPOINT({period})", resolution);
@@ -1214,6 +1290,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The MidPrice indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public MidPrice MIDPRICE(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"MIDPRICE({period})", resolution);
@@ -1237,6 +1314,7 @@ namespace QuantConnect.Algorithm
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null and the symbol is of type TradeBar defaults to the Low property,
/// otherwise it defaults to Value property of BaseData (x => x.Value)</param>
/// <returns>A Minimum indicator that compute the in value and the periods since the min value</returns>
[DocumentationAttribute(Indicators)]
public Minimum MIN(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"MIN({period})", resolution);
@@ -1272,6 +1350,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The momentum indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public Momentum MOM(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"MOM({period})", resolution);
@@ -1295,6 +1374,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The Momersion indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public MomersionIndicator MOMERSION(Symbol symbol, int? minPeriod, int fullPeriod, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"MOMERSION({minPeriod},{fullPeriod})", resolution);
@@ -1318,6 +1398,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The momentum indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public MomentumPercent MOMP(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"MOMP({period})", resolution);
@@ -1340,6 +1421,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The NormalizedAverageTrueRange indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public NormalizedAverageTrueRange NATR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"NATR({period})", resolution);
@@ -1363,6 +1445,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The On Balance Volume indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public OnBalanceVolume OBV(Symbol symbol, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, "OBV", resolution);
@@ -1387,6 +1470,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The PivotPointsHighLow indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public PivotPointsHighLow PPHL(Symbol symbol, int lengthHigh, int lengthLow, int lastStoredValues = 100, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"PPHL({lengthHigh},{lengthLow})", resolution);
@@ -1411,6 +1495,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The PercentagePriceOscillator indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public PercentagePriceOscillator PPO(Symbol symbol, int fastPeriod, int slowPeriod, MovingAverageType movingAverageType, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"PPO({fastPeriod},{slowPeriod})", resolution);
@@ -1435,6 +1520,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>A ParabolicStopAndReverse configured with the specified periods</returns>
[DocumentationAttribute(Indicators)]
public ParabolicStopAndReverse PSAR(Symbol symbol, decimal afStart = 0.02m, decimal afIncrement = 0.02m, decimal afMax = 0.2m, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"PSAR({afStart},{afIncrement},{afMax})", resolution);
@@ -1458,6 +1544,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>A Regression Channel configured with the specified period and number of standard deviation</returns>
[DocumentationAttribute(Indicators)]
public RegressionChannel RC(Symbol symbol, int period, decimal k, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"RC({period},{k})", resolution);
@@ -1481,6 +1568,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The RateOfChange indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public RateOfChange ROC(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"ROC({period})", resolution);
@@ -1504,6 +1592,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The RateOfChangePercent indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public RateOfChangePercent ROCP(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"ROCP({period})", resolution);
@@ -1526,6 +1615,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The RateOfChangeRatio indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public RateOfChangeRatio ROCR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"ROCR({period})", resolution);
@@ -1550,6 +1640,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The RelativeStrengthIndex indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public RelativeStrengthIndex RSI(Symbol symbol, int period, MovingAverageType movingAverageType = MovingAverageType.Wilders, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"RSI({period},{movingAverageType})", resolution);
@@ -1572,6 +1663,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The RelativeVigorIndex indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public RelativeVigorIndex RVI(Symbol symbol, int period, MovingAverageType movingAverageType = MovingAverageType.Simple, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"RVI({period},{movingAverageType})", resolution);
@@ -1595,6 +1687,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The Relative Volume indicator for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public RelativeDailyVolume RDV(Symbol symbol, int period = 2, Resolution resolution = Resolution.Daily, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"RDV({period})", resolution);
@@ -1617,6 +1710,7 @@ namespace QuantConnect.Algorithm
/// <param name="multiplier">Multiplier to calculate basic upper and lower bands width.</param>
/// <param name="movingAverageType">Smoother type for average true range, defaults to Wilders.</param>
/// <param name="resolution">The resolution.</param>
[DocumentationAttribute(Indicators)]
public SuperTrend STR(Symbol symbol, int period, decimal multiplier, MovingAverageType movingAverageType = MovingAverageType.Wilders, Resolution? resolution = null)
{
var name = CreateIndicatorName(symbol, $"STR({period},{multiplier})", resolution);
@@ -1640,6 +1734,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The RollingSharpeRatio indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public SharpeRatio SR(Symbol symbol, int sharpePeriod, decimal riskFreeRate = 0.0m, Resolution ? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"SR({sharpePeriod},{riskFreeRate})", resolution);
@@ -1664,6 +1759,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The SimpleMovingAverage for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public SimpleMovingAverage SMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"SMA({period})", resolution);
@@ -1689,6 +1785,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The SchaffTrendCycle indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public SchaffTrendCycle STC(Symbol symbol, int cyclePeriod, int fastPeriod, int slowPeriod, MovingAverageType movingAverageType = MovingAverageType.Exponential, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"STC({cyclePeriod},{fastPeriod},{slowPeriod})", resolution);
@@ -1711,6 +1808,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The StandardDeviation indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public StandardDeviation STD(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"STD({period})", resolution);
@@ -1733,6 +1831,7 @@ namespace QuantConnect.Algorithm
/// <param name="kPeriod">The sum period of the stochastic. Normally 14</param>
/// <param name="dPeriod">The sum period of the stochastic. Normally 3</param>
/// <returns>Stochastic indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public Stochastic STO(Symbol symbol, int period, int kPeriod, int dPeriod, Resolution? resolution = null)
{
var name = CreateIndicatorName(symbol, $"STO({period},{kPeriod},{dPeriod})", resolution);
@@ -1754,6 +1853,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution.</param>
/// <param name="period">The period of the stochastic. Normally 14</param>
/// <returns>Stochastic indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public Stochastic STO(Symbol symbol, int period, Resolution? resolution = null)
{
return STO(symbol, period, period, 3, resolution);
@@ -1767,6 +1867,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The Sum indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public Sum SUM(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"SUM({period})", resolution);
@@ -1792,6 +1893,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">elects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The calculation using the given tool</returns>
[DocumentationAttribute(Indicators)]
public SwissArmyKnife SWISS(Symbol symbol, int period, double delta, SwissArmyKnifeTool tool, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"SWISS({period},{delta},{tool})", resolution);
@@ -1815,6 +1917,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The T3MovingAverage indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public T3MovingAverage T3(Symbol symbol, int period, decimal volumeFactor = 0.7m, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"T3({period},{volumeFactor})", resolution);
@@ -1837,6 +1940,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The TripleExponentialMovingAverage indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public TripleExponentialMovingAverage TEMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"TEMA({period})", resolution);
@@ -1858,6 +1962,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The TrueRange indicator for the requested symbol.</returns>
[DocumentationAttribute(Indicators)]
public TrueRange TR(Symbol symbol, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, "TR", resolution);
@@ -1880,6 +1985,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The TriangularMovingAverage indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public TriangularMovingAverage TRIMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"TRIMA({period})", resolution);
@@ -1902,6 +2008,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The Trix indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public Trix TRIX(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"TRIX({period})", resolution);
@@ -1926,6 +2033,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The UltimateOscillator indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public UltimateOscillator ULTOSC(Symbol symbol, int period1, int period2, int period3, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"ULTOSC({period1},{period2},{period3})", resolution);
@@ -1948,6 +2056,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The Variance indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public Variance VAR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"VAR({period})", resolution);
@@ -1971,6 +2080,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The VolumeWeightedAveragePrice for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public VolumeWeightedAveragePriceIndicator VWAP(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"VWAP({period})", resolution);
@@ -1991,6 +2101,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="symbol">The symbol whose VWAP we want</param>
/// <returns>The IntradayVWAP for the specified symbol</returns>
[DocumentationAttribute(Indicators)]
public IntradayVwap VWAP(Symbol symbol)
{
var name = CreateIndicatorName(symbol, "VWAP", null);
@@ -2009,6 +2120,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The Williams %R indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public WilliamsPercentR WILR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"WILR({period})", resolution);
@@ -2033,6 +2145,7 @@ namespace QuantConnect.Algorithm
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The WilderMovingAverage for the given parameters</returns>
/// <remarks>WWMA for Welles Wilder Moving Average</remarks>
[DocumentationAttribute(Indicators)]
public WilderMovingAverage WWMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
var name = CreateIndicatorName(symbol, $"WWMA({period})", resolution);
@@ -2056,6 +2169,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <returns>The WilderSwingIndex for the given parameters</returns>
/// <remarks>SI for Wilder Swing Index</remarks>
[DocumentationAttribute(Indicators)]
public WilderSwingIndex SI(Symbol symbol, decimal limitMove, Resolution? resolution = Resolution.Daily)
{
var name = CreateIndicatorName(symbol, "SI", resolution);
@@ -2079,6 +2193,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <returns>The WilderAccumulativeSwingIndex for the given parameters</returns>
/// <remarks>ASI for Wilder Accumulative Swing Index</remarks>
[DocumentationAttribute(Indicators)]
public WilderAccumulativeSwingIndex ASI(Symbol symbol, decimal limitMove, Resolution? resolution = Resolution.Daily)
{
var name = CreateIndicatorName(symbol, "ASI", resolution);
@@ -2099,6 +2214,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbols">The symbols whose Arms Index we want</param>
/// <param name="resolution">The resolution</param>
/// <returns>The Arms Index indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public ArmsIndex TRIN(IEnumerable<Symbol> symbols, Resolution? resolution = null)
{
return TRIN(symbols.ToArray(), resolution);
@@ -2110,6 +2226,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbols">The symbols whose Arms Index we want</param>
/// <param name="resolution">The resolution</param>
/// <returns>The Arms Index indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public ArmsIndex TRIN(Symbol[] symbols, Resolution? resolution = null)
{
var name = CreateIndicatorName(QuantConnect.Symbol.None, "TRIN", resolution ?? GetSubscription(symbols.First()).Resolution);
@@ -2134,6 +2251,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbols">The symbols whose A/D Ratio we want</param>
/// <param name="resolution">The resolution</param>
/// <returns>The Advance/Decline Ratio indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public AdvanceDeclineRatio ADR(IEnumerable<Symbol> symbols, Resolution? resolution = null)
{
var name = CreateIndicatorName(QuantConnect.Symbol.None, "A/D Ratio", resolution ?? GetSubscription(symbols.First()).Resolution);
@@ -2158,6 +2276,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbols">The symbol whose A/D Volume Rate we want</param>
/// <param name="resolution">The resolution</param>
/// <returns>The Advance/Decline Volume Ratio indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public AdvanceDeclineVolumeRatio ADVR(IEnumerable<Symbol> symbols, Resolution? resolution = null)
{
var name = CreateIndicatorName(QuantConnect.Symbol.None, "A/D Volume Rate", resolution ?? GetSubscription(symbols.First()).Resolution);
@@ -2183,6 +2302,7 @@ namespace QuantConnect.Algorithm
/// <param name="type">The indicator type, for example, 'SMA(5)'</param>
/// <param name="resolution">The resolution requested</param>
/// <returns>A unique for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public string CreateIndicatorName(Symbol symbol, FormattableString type, Resolution? resolution)
{
return CreateIndicatorName(symbol, Invariant(type), resolution);
@@ -2195,6 +2315,7 @@ namespace QuantConnect.Algorithm
/// <param name="type">The indicator type, for example, 'SMA(5)'</param>
/// <param name="resolution">The resolution requested</param>
/// <returns>A unique for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public string CreateIndicatorName(Symbol symbol, string type, Resolution? resolution)
{
if (!resolution.HasValue)
@@ -2285,6 +2406,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
[DocumentationAttribute(ConsolidatingData)]
[DocumentationAttribute(Indicators)]
public void RegisterIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution), selector ?? (x => x.Value));
@@ -2298,6 +2421,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
[DocumentationAttribute(ConsolidatingData)]
[DocumentationAttribute(Indicators)]
public void RegisterIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, TimeSpan? resolution = null, Func<IBaseData, decimal> selector = null)
{
RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution), selector ?? (x => x.Value));
@@ -2311,6 +2436,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="consolidator">The consolidator to receive raw subscription data</param>
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
[DocumentationAttribute(ConsolidatingData)]
[DocumentationAttribute(Indicators)]
public void RegisterIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, IDataConsolidator consolidator, Func<IBaseData, decimal> selector = null)
{
// default our selector to the Value property on BaseData
@@ -2334,6 +2461,8 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">The symbol to register against</param>
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
[DocumentationAttribute(ConsolidatingData)]
[DocumentationAttribute(Indicators)]
public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, Resolution? resolution = null)
where T : IBaseData
{
@@ -2348,6 +2477,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
[DocumentationAttribute(ConsolidatingData)]
[DocumentationAttribute(Indicators)]
public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, Resolution? resolution, Func<IBaseData, T> selector)
where T : IBaseData
{
@@ -2362,6 +2493,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
[DocumentationAttribute(ConsolidatingData)]
[DocumentationAttribute(Indicators)]
public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, TimeSpan? resolution, Func<IBaseData, T> selector = null)
where T : IBaseData
{
@@ -2376,6 +2509,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="consolidator">The consolidator to receive raw subscription data</param>
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
[DocumentationAttribute(ConsolidatingData)]
[DocumentationAttribute(Indicators)]
public void RegisterIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, IDataConsolidator consolidator, Func<IBaseData, T> selector = null)
where T : IBaseData
{
@@ -2419,6 +2554,8 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The given indicator</returns>
[DocumentationAttribute(HistoricalData)]
[DocumentationAttribute(Indicators)]
public IndicatorBase<IndicatorDataPoint> WarmUpIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
{
resolution = GetResolution(symbol, resolution);
@@ -2434,6 +2571,8 @@ namespace QuantConnect.Algorithm
/// <param name="period">The necessary period to warm up the indicator</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The given indicator</returns>
[DocumentationAttribute(HistoricalData)]
[DocumentationAttribute(Indicators)]
public IndicatorBase<IndicatorDataPoint> WarmUpIndicator(Symbol symbol, IndicatorBase<IndicatorDataPoint> indicator, TimeSpan period, Func<IBaseData, decimal> selector = null)
{
var history = GetIndicatorWarmUpHistory(symbol, indicator, period);
@@ -2460,6 +2599,8 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to the Value property of BaseData (x => x.Value)</param>
/// <returns>The given indicator</returns>
[DocumentationAttribute(HistoricalData)]
[DocumentationAttribute(Indicators)]
public IndicatorBase<T> WarmUpIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, Resolution? resolution = null, Func<IBaseData, T> selector = null)
where T : class, IBaseData
{
@@ -2476,6 +2617,8 @@ namespace QuantConnect.Algorithm
/// <param name="period">The necessary period to warm up the indicator</param>
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
/// <returns>The given indicator</returns>
[DocumentationAttribute(HistoricalData)]
[DocumentationAttribute(Indicators)]
public IndicatorBase<T> WarmUpIndicator<T>(Symbol symbol, IndicatorBase<T> indicator, TimeSpan period, Func<IBaseData, T> selector = null)
where T : class, IBaseData
{
@@ -2586,6 +2729,8 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The resolution for the consolidator, if null, uses the resolution from subscription</param>
/// <param name="dataType">The data type for this consolidator, if null, uses TradeBar over QuoteBar if present</param>
/// <returns>The new default consolidator</returns>
[DocumentationAttribute(ConsolidatingData)]
[DocumentationAttribute(Indicators)]
public IDataConsolidator ResolveConsolidator(Symbol symbol, Resolution? resolution, Type dataType = null)
{
TimeSpan? timeSpan = null;
@@ -2603,6 +2748,8 @@ namespace QuantConnect.Algorithm
/// <param name="timeSpan">The requested time span for the consolidator, if null, uses the resolution from subscription</param>
/// <param name="dataType">The data type for this consolidator, if null, uses TradeBar over QuoteBar if present</param>
/// <returns>The new default consolidator</returns>
[DocumentationAttribute(ConsolidatingData)]
[DocumentationAttribute(Indicators)]
public IDataConsolidator ResolveConsolidator(Symbol symbol, TimeSpan? timeSpan, Type dataType = null)
{
var tickType = dataType != null ? LeanData.GetCommonTickTypeForCommonDataTypes(dataType, symbol.SecurityType) : (TickType?)null;
@@ -2633,6 +2780,7 @@ namespace QuantConnect.Algorithm
/// <param name="consolidatorInputType">The desired input type of the consolidator, such as TradeBar or QuoteBar</param>
/// <param name="tickType">Trade or Quote. Optional, defaults to trade</param>
/// <returns>A new consolidator matching the requested parameters</returns>
[DocumentationAttribute(ConsolidatingData)]
public static IDataConsolidator CreateConsolidator(TimeSpan period, Type consolidatorInputType, TickType? tickType = null)
{
// if our type can be used as a trade bar, then let's just make one of those
@@ -2689,6 +2837,7 @@ namespace QuantConnect.Algorithm
/// <param name="period">The consolidation period</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, Resolution period, Action<TradeBar> handler)
{
return Consolidate(symbol, period.ToTimeSpan(), TickType.Trade, handler);
@@ -2701,6 +2850,7 @@ namespace QuantConnect.Algorithm
/// <param name="period">The consolidation period</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, TimeSpan period, Action<TradeBar> handler)
{
return Consolidate(symbol, period, TickType.Trade, handler);
@@ -2713,6 +2863,7 @@ namespace QuantConnect.Algorithm
/// <param name="period">The consolidation period</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, Resolution period, Action<QuoteBar> handler)
{
return Consolidate(symbol, period.ToTimeSpan(), TickType.Quote, handler);
@@ -2725,6 +2876,7 @@ namespace QuantConnect.Algorithm
/// <param name="period">The consolidation period</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, TimeSpan period, Action<QuoteBar> handler)
{
return Consolidate(symbol, period, TickType.Quote, handler);
@@ -2738,6 +2890,7 @@ namespace QuantConnect.Algorithm
/// <param name="period">The consolidation period</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate<T>(Symbol symbol, TimeSpan period, Action<T> handler)
where T : class, IBaseData
{
@@ -2757,6 +2910,7 @@ namespace QuantConnect.Algorithm
/// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate<T>(Symbol symbol, Resolution period, TickType? tickType, Action<T> handler)
where T : class, IBaseData
{
@@ -2772,6 +2926,7 @@ namespace QuantConnect.Algorithm
/// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate<T>(Symbol symbol, TimeSpan period, TickType? tickType, Action<T> handler)
where T : class, IBaseData
{
@@ -2792,6 +2947,7 @@ namespace QuantConnect.Algorithm
/// <param name="calendar">The consolidation calendar</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, Func<DateTime, CalendarInfo> calendar, Action<QuoteBar> handler)
{
return Consolidate(symbol, calendar, TickType.Quote, handler);
@@ -2804,6 +2960,7 @@ namespace QuantConnect.Algorithm
/// <param name="calendar">The consolidation calendar</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, Func<DateTime, CalendarInfo> calendar, Action<TradeBar> handler)
{
return Consolidate(symbol, calendar, TickType.Trade, handler);
@@ -2817,6 +2974,7 @@ namespace QuantConnect.Algorithm
/// <param name="calendar">The consolidation calendar</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate<T>(Symbol symbol, Func<DateTime, CalendarInfo> calendar, Action<T> handler)
where T : class, IBaseData
{
@@ -2836,6 +2994,7 @@ namespace QuantConnect.Algorithm
/// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
private IDataConsolidator Consolidate<T>(Symbol symbol, Func<DateTime, CalendarInfo> calendar, TickType? tickType, Action<T> handler)
where T : class, IBaseData
{
@@ -2853,6 +3012,7 @@ namespace QuantConnect.Algorithm
/// Adds the provided consolidator and asserts the handler T type is assignable from the consolidator output,
/// if not will throw <see cref="ArgumentException"/>
/// </summary>
[DocumentationAttribute(ConsolidatingData)]
private void AddConsolidator<T>(Symbol symbol, IDataConsolidator consolidator, Action<T> handler)
{
if (!typeof(T).IsAssignableFrom(consolidator.OutputType))
@@ -2876,6 +3036,7 @@ namespace QuantConnect.Algorithm
SubscriptionManager.AddConsolidator(symbol, consolidator);
}
[DocumentationAttribute(ConsolidatingData)]
private IDataConsolidator CreateConsolidator(Func<DateTime, CalendarInfo> calendar, Type consolidatorInputType, TickType tickType)
{
// if our type can be used as a trade bar, then let's just make one of those

View File

@@ -45,6 +45,7 @@ namespace QuantConnect.Algorithm
/// Access to the runtime statistics property. User provided statistics.
/// </summary>
/// <remarks> RuntimeStatistics are displayed in the head banner in live trading</remarks>
[DocumentationAttribute(Charting)]
public ConcurrentDictionary<string, string> RuntimeStatistics { get; } = new ConcurrentDictionary<string, string>();
/// <summary>
@@ -52,6 +53,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="chart">Chart object to add to collection.</param>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void AddChart(Chart chart)
{
_charts.TryAdd(chart.Name, chart);
@@ -63,6 +65,7 @@ namespace QuantConnect.Algorithm
/// <param name="series">Name of the plot series</param>
/// <param name="value">Value to plot</param>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string series, decimal value)
{
//By default plot to the primary chart:
@@ -74,6 +77,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <remarks> Record(string series, int value)</remarks>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Record(string series, int value)
{
Plot(series, value);
@@ -83,6 +87,7 @@ namespace QuantConnect.Algorithm
/// Plot a chart using string series name, with double value. Alias of Plot();
/// </summary>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Record(string series, double value)
{
Plot(series, value);
@@ -94,6 +99,7 @@ namespace QuantConnect.Algorithm
/// <param name="series"></param>
/// <param name="value"></param>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Record(string series, decimal value)
{
//By default plot to the primary chart:
@@ -104,6 +110,7 @@ namespace QuantConnect.Algorithm
/// Plot a chart using string series name, with double value.
/// </summary>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string series, double value) {
Plot(series, value.SafeDecimalCast());
}
@@ -112,6 +119,7 @@ namespace QuantConnect.Algorithm
/// Plot a chart using string series name, with int value.
/// </summary>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string series, int value)
{
Plot(series, (decimal)value);
@@ -121,6 +129,7 @@ namespace QuantConnect.Algorithm
///Plot a chart using string series name, with float value.
/// </summary>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string series, float value)
{
Plot(series, (decimal)value);
@@ -130,6 +139,7 @@ namespace QuantConnect.Algorithm
/// Plot a chart to string chart name, using string series name, with double value.
/// </summary>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string chart, string series, double value)
{
Plot(chart, series, value.SafeDecimalCast());
@@ -139,6 +149,7 @@ namespace QuantConnect.Algorithm
/// Plot a chart to string chart name, using string series name, with int value
/// </summary>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string chart, string series, int value)
{
Plot(chart, series, (decimal)value);
@@ -148,6 +159,7 @@ namespace QuantConnect.Algorithm
/// Plot a chart to string chart name, using string series name, with float value
/// </summary>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string chart, string series, float value)
{
Plot(chart, series, (decimal)value);
@@ -159,6 +171,7 @@ namespace QuantConnect.Algorithm
/// <param name="chart">Chart name</param>
/// <param name="series">Series name</param>
/// <param name="value">Value of the point</param>
[DocumentationAttribute(Charting)]
public void Plot(string chart, string series, decimal value)
{
// Check if chart/series names are reserved
@@ -209,6 +222,7 @@ namespace QuantConnect.Algorithm
/// <param name="series">The series name</param>
/// <param name="seriesType">The type of series, i.e, Scatter</param>
/// <param name="unit">The unit of the y axis, usually $</param>
[DocumentationAttribute(Charting)]
public void AddSeries(string chart, string series, SeriesType seriesType, string unit = "$")
{
Chart c;
@@ -226,6 +240,7 @@ namespace QuantConnect.Algorithm
/// <param name="chart">The chart's name</param>
/// <param name="indicators">The indicatorsto plot</param>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot<T>(string chart, params IndicatorBase<T>[] indicators)
where T : IBaseData
{
@@ -238,6 +253,8 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Automatically plots each indicator when a new value is available
/// </summary>
[DocumentationAttribute(Charting)]
[DocumentationAttribute(Indicators)]
public void PlotIndicator<T>(string chart, params IndicatorBase<T>[] indicators)
where T : IBaseData
{
@@ -257,6 +274,8 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Automatically plots each indicator when a new value is available, optionally waiting for indicator.IsReady to return true
/// </summary>
[DocumentationAttribute(Charting)]
[DocumentationAttribute(Indicators)]
public void PlotIndicator<T>(string chart, bool waitForReady, params IndicatorBase<T>[] indicators)
where T : IBaseData
{
@@ -282,6 +301,7 @@ namespace QuantConnect.Algorithm
/// <param name="name">Name of your runtime statistic</param>
/// <param name="value">String value of your runtime statistic</param>
/// <seealso cref="LiveMode"/>
[DocumentationAttribute(Charting)]
public void SetRuntimeStatistic(string name, string value)
{
RuntimeStatistics.AddOrUpdate(name, value);
@@ -292,6 +312,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="name">Name of your runtime statistic</param>
/// <param name="value">Decimal value of your runtime statistic</param>
[DocumentationAttribute(Charting)]
public void SetRuntimeStatistic(string name, decimal value)
{
SetRuntimeStatistic(name, value.ToString(CultureInfo.InvariantCulture));
@@ -302,6 +323,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="name">Name of your runtime statistic</param>
/// <param name="value">Int value of your runtime statistic</param>
[DocumentationAttribute(Charting)]
public void SetRuntimeStatistic(string name, int value)
{
SetRuntimeStatistic(name, value.ToStringInvariant());
@@ -312,17 +334,19 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="name">Name of your runtime statistic</param>
/// <param name="value">Double value of your runtime statistic</param>
[DocumentationAttribute(Charting)]
public void SetRuntimeStatistic(string name, double value)
{
SetRuntimeStatistic(name, value.ToString(CultureInfo.InvariantCulture));
}
/// <summary>
/// Get the chart updates by fetch the recent points added and return for dynamic plotting.
/// Get the chart updates by fetch the recent points added and return for dynamic Charting.
/// </summary>
/// <param name="clearChartData"></param>
/// <returns>List of chart updates since the last request</returns>
/// <remarks>GetChartUpdates returns the latest updates since previous request.</remarks>
[DocumentationAttribute(Charting)]
public List<Chart> GetChartUpdates(bool clearChartData = false)
{
var updates = _charts.Select(x => x.Value).Select(chart => chart.GetUpdates()).ToList();

View File

@@ -59,6 +59,7 @@ namespace QuantConnect.Algorithm
/// <param name="ticker">Key/Ticker for data</param>
/// <param name="resolution">Resolution of the data</param>
/// <returns>The new <see cref="Security"/></returns>
[DocumentationAttribute(AddingData)]
public Security AddData(PyObject type, string ticker, Resolution? resolution = null)
{
return AddData(type, ticker, resolution, null, false, 1m);
@@ -82,6 +83,7 @@ namespace QuantConnect.Algorithm
/// Adding the three unused parameters makes it choose the correct method when using a string or Symbol. This is
/// due to pythonnet's method precedence, as viewable here: https://github.com/QuantConnect/pythonnet/blob/9e29755c54e6008cb016e3dd9d75fbd8cd19fcf7/src/runtime/methodbinder.cs#L215
/// </remarks>
[DocumentationAttribute(AddingData)]
public Security AddData(PyObject type, Symbol underlying, Resolution? resolution = null)
{
return AddData(type, underlying, resolution, null, false, 1m);
@@ -99,6 +101,7 @@ namespace QuantConnect.Algorithm
/// <param name="fillDataForward">When no data available on a tradebar, return the last data that was generated</param>
/// <param name="leverage">Custom leverage per security</param>
/// <returns>The new <see cref="Security"/></returns>
[DocumentationAttribute(AddingData)]
public Security AddData(PyObject type, string ticker, Resolution? resolution, DateTimeZone timeZone, bool fillDataForward = false, decimal leverage = 1.0m)
{
return AddData(type.CreateType(), ticker, resolution, timeZone, fillDataForward, leverage);
@@ -124,6 +127,7 @@ namespace QuantConnect.Algorithm
/// Adding the three unused parameters makes it choose the correct method when using a string or Symbol. This is
/// due to pythonnet's method precedence, as viewable here: https://github.com/QuantConnect/pythonnet/blob/9e29755c54e6008cb016e3dd9d75fbd8cd19fcf7/src/runtime/methodbinder.cs#L215
/// </remarks>
[DocumentationAttribute(AddingData)]
public Security AddData(PyObject type, Symbol underlying, Resolution? resolution, DateTimeZone timeZone, bool fillDataForward = false, decimal leverage = 1.0m)
{
return AddData(type.CreateType(), underlying, resolution, timeZone, fillDataForward, leverage);
@@ -141,6 +145,7 @@ namespace QuantConnect.Algorithm
/// <param name="fillDataForward">When no data available on a tradebar, return the last data that was generated</param>
/// <param name="leverage">Custom leverage per security</param>
/// <returns>The new <see cref="Security"/></returns>
[DocumentationAttribute(AddingData)]
public Security AddData(Type dataType, string ticker, Resolution? resolution, DateTimeZone timeZone, bool fillDataForward = false, decimal leverage = 1.0m)
{
// NOTE: Invoking methods on BaseData w/out setting the symbol may provide unexpected behavior
@@ -185,6 +190,7 @@ namespace QuantConnect.Algorithm
/// Adding the three unused parameters makes it choose the correct method when using a string or Symbol. This is
/// due to pythonnet's method precedence, as viewable here: https://github.com/QuantConnect/pythonnet/blob/9e29755c54e6008cb016e3dd9d75fbd8cd19fcf7/src/runtime/methodbinder.cs#L215
/// </remarks>
[DocumentationAttribute(AddingData)]
public Security AddData(Type dataType, Symbol underlying, Resolution? resolution = null, DateTimeZone timeZone = null, bool fillDataForward = false, decimal leverage = 1.0m)
{
var symbol = QuantConnect.Symbol.CreateBase(dataType, underlying, Market.USA);
@@ -204,6 +210,7 @@ namespace QuantConnect.Algorithm
/// <param name="fillDataForward">When no data available on a tradebar, return the last data that was generated</param>
/// <param name="leverage">Custom leverage per security</param>
/// <returns>The new <see cref="Security"/></returns>
[DocumentationAttribute(AddingData)]
public Security AddData(PyObject type, string ticker, SymbolProperties properties, SecurityExchangeHours exchangeHours, Resolution? resolution = null, bool fillDataForward = false, decimal leverage = 1.0m)
{
// Get the right key for storage of base type symbols
@@ -224,6 +231,7 @@ namespace QuantConnect.Algorithm
/// <param name="optionFilter">Filter to apply to option contracts loaded as part of the universe</param>
/// <returns>The new Option security, containing a Future as its underlying.</returns>
/// <exception cref="ArgumentException">The symbol provided is not canonical.</exception>
[DocumentationAttribute(AddingData)]
public void AddFutureOption(Symbol futureSymbol, PyObject optionFilter)
{
Func<OptionFilterUniverse, OptionFilterUniverse> optionFilterUniverse;
@@ -276,6 +284,7 @@ namespace QuantConnect.Algorithm
/// will be executed on day changes in the NewYork time zone (<see cref="TimeZones.NewYork"/>
/// </summary>
/// <param name="pyObject">Defines an initial coarse selection</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(PyObject pyObject)
{
Func<IEnumerable<CoarseFundamental>, object> coarseFunc;
@@ -309,6 +318,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="pyObject">Defines an initial coarse selection or a universe</param>
/// <param name="pyfine">Defines a more detailed selection with access to more data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(PyObject pyObject, PyObject pyfine)
{
Func<IEnumerable<CoarseFundamental>, object> coarseFunc;
@@ -340,6 +350,7 @@ namespace QuantConnect.Algorithm
/// <param name="name">A unique name for this universe</param>
/// <param name="resolution">The resolution this universe should be triggered on</param>
/// <param name="pySelector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(string name, Resolution resolution, PyObject pySelector)
{
var selector = pySelector.ConvertToDelegate<Func<DateTime, object>>();
@@ -352,6 +363,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="name">A unique name for this universe</param>
/// <param name="pySelector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(string name, PyObject pySelector)
{
var selector = pySelector.ConvertToDelegate<Func<DateTime, object>>();
@@ -367,6 +379,7 @@ namespace QuantConnect.Algorithm
/// <param name="market">The market of the universe</param>
/// <param name="universeSettings">The subscription settings used for securities added from this universe</param>
/// <param name="pySelector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, PyObject pySelector)
{
var selector = pySelector.ConvertToDelegate<Func<DateTime, object>>();
@@ -381,6 +394,7 @@ namespace QuantConnect.Algorithm
/// <param name="T">The data type</param>
/// <param name="name">A unique name for this universe</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(PyObject T, string name, PyObject selector)
{
return AddUniverse(T.CreateType(), SecurityType.Equity, name, Resolution.Daily, Market.USA, UniverseSettings, selector);
@@ -395,6 +409,7 @@ namespace QuantConnect.Algorithm
/// <param name="name">A unique name for this universe</param>
/// <param name="resolution">The epected resolution of the universe data</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(PyObject T, string name, Resolution resolution, PyObject selector)
{
return AddUniverse(T.CreateType(), SecurityType.Equity, name, resolution, Market.USA, UniverseSettings, selector);
@@ -410,6 +425,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The epected resolution of the universe data</param>
/// <param name="universeSettings">The settings used for securities added by this universe</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(PyObject T, string name, Resolution resolution, UniverseSettings universeSettings, PyObject selector)
{
return AddUniverse(T.CreateType(), SecurityType.Equity, name, resolution, Market.USA, universeSettings, selector);
@@ -424,6 +440,7 @@ namespace QuantConnect.Algorithm
/// <param name="name">A unique name for this universe</param>
/// <param name="universeSettings">The settings used for securities added by this universe</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(PyObject T, string name, UniverseSettings universeSettings, PyObject selector)
{
return AddUniverse(T.CreateType(), SecurityType.Equity, name, Resolution.Daily, Market.USA, universeSettings, selector);
@@ -439,6 +456,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The epected resolution of the universe data</param>
/// <param name="market">The market for selected symbols</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(PyObject T, SecurityType securityType, string name, Resolution resolution, string market, PyObject selector)
{
return AddUniverse(T.CreateType(), securityType, name, resolution, market, UniverseSettings, selector);
@@ -454,6 +472,7 @@ namespace QuantConnect.Algorithm
/// <param name="market">The market for selected symbols</param>
/// <param name="universeSettings">The subscription settings to use for newly created subscriptions</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(PyObject T, SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, PyObject selector)
{
return AddUniverse(T.CreateType(), securityType, name, resolution, market, universeSettings, selector);
@@ -469,6 +488,7 @@ namespace QuantConnect.Algorithm
/// <param name="market">The market for selected symbols</param>
/// <param name="universeSettings">The subscription settings to use for newly created subscriptions</param>
/// <param name="pySelector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(Type dataType, SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, PyObject pySelector)
{
var marketHoursDbEntry = MarketHoursDatabase.GetEntry(market, name, securityType);
@@ -495,6 +515,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="universe">The universe we want to chain an option universe selection model too</param>
/// <param name="optionFilter">The option filter universe to use</param>
[DocumentationAttribute(Universes)]
public void AddUniverseOptions(PyObject universe, PyObject optionFilter)
{
Func<OptionFilterUniverse, OptionFilterUniverse> convertedOptionChain;
@@ -521,6 +542,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
[DocumentationAttribute(Indicators)]
[DocumentationAttribute(ConsolidatingData)]
public void RegisterIndicator(Symbol symbol, PyObject indicator, Resolution? resolution = null, PyObject selector = null)
{
RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution), selector);
@@ -534,6 +557,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param>
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
[DocumentationAttribute(Indicators)]
[DocumentationAttribute(ConsolidatingData)]
public void RegisterIndicator(Symbol symbol, PyObject indicator, TimeSpan? resolution = null, PyObject selector = null)
{
RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution), selector);
@@ -547,6 +572,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="pyObject">The python object that it is trying to register with, could be consolidator or a timespan</param>
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
[DocumentationAttribute(Indicators)]
[DocumentationAttribute(ConsolidatingData)]
public void RegisterIndicator(Symbol symbol, PyObject indicator, PyObject pyObject, PyObject selector = null)
{
try
@@ -594,6 +621,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator to receive data from the consolidator</param>
/// <param name="consolidator">The consolidator to receive raw subscription data</param>
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
[DocumentationAttribute(Indicators)]
[DocumentationAttribute(ConsolidatingData)]
public void RegisterIndicator(Symbol symbol, PyObject indicator, IDataConsolidator consolidator, PyObject selector = null)
{
// TODO: to be removed when https://github.com/QuantConnect/pythonnet/issues/62 is solved
@@ -627,6 +656,8 @@ namespace QuantConnect.Algorithm
/// <param name="indicator">The indicator we want to warm up</param>
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
[DocumentationAttribute(Indicators)]
[DocumentationAttribute(HistoricalData)]
public void WarmUpIndicator(Symbol symbol, PyObject indicator, Resolution? resolution = null, PyObject selector = null)
{
// TODO: to be removed when https://github.com/QuantConnect/pythonnet/issues/62 is solved
@@ -659,6 +690,7 @@ namespace QuantConnect.Algorithm
/// <param name="series">Name of the plot series</param>
/// <param name="pyObject">PyObject with the value to plot</param>
/// <seealso cref="Plot(string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string series, PyObject pyObject)
{
using (Py.GIL())
@@ -685,6 +717,7 @@ namespace QuantConnect.Algorithm
/// <param name="third">The third indicator to plot</param>
/// <param name="fourth">The fourth indicator to plot</param>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string chart, Indicator first, Indicator second = null, Indicator third = null, Indicator fourth = null)
{
Plot(chart, new[] { first, second, third, fourth }.Where(x => x != null).ToArray());
@@ -699,6 +732,7 @@ namespace QuantConnect.Algorithm
/// <param name="third">The third indicator to plot</param>
/// <param name="fourth">The fourth indicator to plot</param>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string chart, BarIndicator first, BarIndicator second = null, BarIndicator third = null, BarIndicator fourth = null)
{
Plot(chart, new[] { first, second, third, fourth }.Where(x => x != null).ToArray());
@@ -713,6 +747,7 @@ namespace QuantConnect.Algorithm
/// <param name="third">The third indicator to plot</param>
/// <param name="fourth">The fourth indicator to plot</param>
/// <seealso cref="Plot(string,string,decimal)"/>
[DocumentationAttribute(Charting)]
public void Plot(string chart, TradeBarIndicator first, TradeBarIndicator second = null, TradeBarIndicator third = null, TradeBarIndicator fourth = null)
{
Plot(chart, new[] { first, second, third, fourth }.Where(x => x != null).ToArray());
@@ -721,6 +756,8 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Automatically plots each indicator when a new value is available
/// </summary>
[DocumentationAttribute(Charting)]
[DocumentationAttribute(Indicators)]
public void PlotIndicator(string chart, PyObject first, PyObject second = null, PyObject third = null, PyObject fourth = null)
{
var array = GetIndicatorArray(first, second, third, fourth);
@@ -730,6 +767,8 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Automatically plots each indicator when a new value is available
/// </summary>
[DocumentationAttribute(Charting)]
[DocumentationAttribute(Indicators)]
public void PlotIndicator(string chart, bool waitForReady, PyObject first, PyObject second = null, PyObject third = null, PyObject fourth = null)
{
var array = GetIndicatorArray(first, second, third, fourth);
@@ -745,6 +784,7 @@ namespace QuantConnect.Algorithm
/// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param>
/// <param name="fieldName">The name of the field being selected</param>
/// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns>
[DocumentationAttribute(Indicators)]
public FilteredIdentity FilteredIdentity(Symbol symbol, PyObject selector = null, PyObject filter = null, string fieldName = null)
{
var resolution = GetSubscription(symbol).Resolution;
@@ -761,6 +801,7 @@ namespace QuantConnect.Algorithm
/// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param>
/// <param name="fieldName">The name of the field being selected</param>
/// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns>
[DocumentationAttribute(Indicators)]
public FilteredIdentity FilteredIdentity(Symbol symbol, Resolution resolution, PyObject selector = null, PyObject filter = null, string fieldName = null)
{
var name = CreateIndicatorName(symbol, fieldName ?? "close", resolution);
@@ -781,6 +822,7 @@ namespace QuantConnect.Algorithm
/// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param>
/// <param name="fieldName">The name of the field being selected</param>
/// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns>
[DocumentationAttribute(Indicators)]
public FilteredIdentity FilteredIdentity(Symbol symbol, TimeSpan resolution, PyObject selector = null, PyObject filter = null, string fieldName = null)
{
var name = $"{symbol}({fieldName ?? "close"}_{resolution.ToStringInvariant(null)})";
@@ -799,6 +841,7 @@ namespace QuantConnect.Algorithm
/// <param name="periods">The number of bars to request</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>A python dictionary with pandas DataFrame containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public PyObject History(PyObject tickers, int periods, Resolution? resolution = null)
{
var symbols = tickers.ConvertToSymbolEnumerable();
@@ -813,6 +856,7 @@ namespace QuantConnect.Algorithm
/// <param name="span">The span over which to retrieve recent historical data</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>A python dictionary with pandas DataFrame containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public PyObject History(PyObject tickers, TimeSpan span, Resolution? resolution = null)
{
var symbols = tickers.ConvertToSymbolEnumerable();
@@ -827,6 +871,7 @@ namespace QuantConnect.Algorithm
/// <param name="end">The end time in the algorithm's time zone</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>A python dictionary with pandas DataFrame containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public PyObject History(PyObject tickers, DateTime start, DateTime end, Resolution? resolution = null)
{
var symbols = tickers.ConvertToSymbolEnumerable();
@@ -842,6 +887,7 @@ namespace QuantConnect.Algorithm
/// <param name="end">The end time in the algorithm's time zone</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>pandas.DataFrame containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public PyObject History(PyObject type, PyObject tickers, DateTime start, DateTime end, Resolution? resolution = null)
{
var symbols = tickers.ConvertToSymbolEnumerable();
@@ -870,6 +916,7 @@ namespace QuantConnect.Algorithm
/// <param name="periods">The number of bars to request</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>pandas.DataFrame containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public PyObject History(PyObject type, PyObject tickers, int periods, Resolution? resolution = null)
{
var symbols = tickers.ConvertToSymbolEnumerable();
@@ -900,6 +947,7 @@ namespace QuantConnect.Algorithm
/// <param name="span">The span over which to retrieve recent historical data</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>pandas.DataFrame containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public PyObject History(PyObject type, PyObject tickers, TimeSpan span, Resolution? resolution = null)
{
return History(type, tickers, Time - span, Time, resolution);
@@ -914,6 +962,7 @@ namespace QuantConnect.Algorithm
/// <param name="end">The end time in the algorithm's time zone</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>pandas.DataFrame containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public PyObject History(PyObject type, Symbol symbol, DateTime start, DateTime end, Resolution? resolution = null)
{
var security = Securities[symbol];
@@ -941,6 +990,7 @@ namespace QuantConnect.Algorithm
/// <param name="periods">The number of bars to request</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>pandas.DataFrame containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public PyObject History(PyObject type, Symbol symbol, int periods, Resolution? resolution = null)
{
if (resolution == Resolution.Tick) throw new ArgumentException("History functions that accept a 'periods' parameter can not be used with Resolution.Tick");
@@ -960,6 +1010,7 @@ namespace QuantConnect.Algorithm
/// <param name="span">The span over which to retrieve recent historical data</param>
/// <param name="resolution">The resolution to request</param>
/// <returns>pandas.DataFrame containing the requested historical data</returns>
[DocumentationAttribute(HistoricalData)]
public PyObject History(PyObject type, Symbol symbol, TimeSpan span, Resolution? resolution = null)
{
return History(type, symbol, Time - span, Time, resolution);
@@ -970,6 +1021,9 @@ namespace QuantConnect.Algorithm
/// the benchmark at each date/time requested
/// </summary>
/// <param name="benchmark">The benchmark producing function</param>
[DocumentationAttribute(TradingAndOrders)]
[DocumentationAttribute(SecuritiesAndPortfolio)]
[DocumentationAttribute(Indicators)]
public void SetBenchmark(PyObject benchmark)
{
using (Py.GIL())
@@ -989,6 +1043,7 @@ namespace QuantConnect.Algorithm
/// This can be used to set a custom brokerage model.
/// </summary>
/// <param name="model">The brokerage model to use</param>
[DocumentationAttribute(Modeling)]
public void SetBrokerageModel(PyObject model)
{
IBrokerageModel brokerageModel;
@@ -1004,6 +1059,8 @@ namespace QuantConnect.Algorithm
/// Sets the security initializer function, used to initialize/configure securities after creation
/// </summary>
/// <param name="securityInitializer">The security initializer function or class</param>
[DocumentationAttribute(AddingData)]
[DocumentationAttribute(Modeling)]
public void SetSecurityInitializer(PyObject securityInitializer)
{
var securityInitializer1 = PythonUtil.ToAction<Security>(securityInitializer);
@@ -1023,6 +1080,8 @@ namespace QuantConnect.Algorithm
/// <param name="address">A string containing the URI to download</param>
/// <param name="headers">Defines header values to add to the request</param>
/// <returns>The requested resource as a <see cref="string"/></returns>
[DocumentationAttribute(AddingData)]
[DocumentationAttribute(MachineLearning)]
public string Download(string address, PyObject headers) => Download(address, headers, null, null);
/// <summary>
@@ -1034,6 +1093,8 @@ namespace QuantConnect.Algorithm
/// <param name="userName">The user name associated with the credentials</param>
/// <param name="password">The password for the user name associated with the credentials</param>
/// <returns>The requested resource as a <see cref="string"/></returns>
[DocumentationAttribute(AddingData)]
[DocumentationAttribute(MachineLearning)]
public string Download(string address, PyObject headers, string userName, string password)
{
var dict = new Dictionary<string, string>();
@@ -1068,6 +1129,7 @@ namespace QuantConnect.Algorithm
/// <param name="message">Message to send to debug console</param>
/// <seealso cref="Log(PyObject)"/>
/// <seealso cref="Error(PyObject)"/>
[DocumentationAttribute(Logging)]
public void Debug(PyObject message)
{
Debug(message.ToSafeString());
@@ -1079,6 +1141,7 @@ namespace QuantConnect.Algorithm
/// <param name="message">Message to display in errors grid</param>
/// <seealso cref="Debug(PyObject)"/>
/// <seealso cref="Log(PyObject)"/>
[DocumentationAttribute(Logging)]
public void Error(PyObject message)
{
Error(message.ToSafeString());
@@ -1090,6 +1153,7 @@ namespace QuantConnect.Algorithm
/// <param name="message">String message to log.</param>
/// <seealso cref="Debug(PyObject)"/>
/// <seealso cref="Error(PyObject)"/>
[DocumentationAttribute(Logging)]
public void Log(PyObject message)
{
Log(message.ToSafeString());
@@ -1099,6 +1163,7 @@ namespace QuantConnect.Algorithm
/// Terminate the algorithm after processing the current event handler.
/// </summary>
/// <param name="message">Exit message to display on quitting</param>
[DocumentationAttribute(Logging)]
public void Quit(PyObject message)
{
Quit(message.ToSafeString());
@@ -1111,6 +1176,7 @@ namespace QuantConnect.Algorithm
/// <param name="period">The consolidation period</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, Resolution period, PyObject handler)
{
return Consolidate(symbol, period.ToTimeSpan(), null, handler);
@@ -1124,6 +1190,7 @@ namespace QuantConnect.Algorithm
/// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, Resolution period, TickType? tickType, PyObject handler)
{
return Consolidate(symbol, period.ToTimeSpan(), tickType, handler);
@@ -1136,6 +1203,7 @@ namespace QuantConnect.Algorithm
/// <param name="period">The consolidation period</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, TimeSpan period, PyObject handler)
{
return Consolidate(symbol, period, null, handler);
@@ -1149,6 +1217,7 @@ namespace QuantConnect.Algorithm
/// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, TimeSpan period, TickType? tickType, PyObject handler)
{
// resolve consolidator input subscription
@@ -1174,6 +1243,7 @@ namespace QuantConnect.Algorithm
/// <param name="calendar">The consolidation calendar</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
public IDataConsolidator Consolidate(Symbol symbol, Func<DateTime, CalendarInfo> calendar, PyObject handler)
{
return Consolidate(symbol, calendar, null, handler);
@@ -1183,6 +1253,8 @@ namespace QuantConnect.Algorithm
/// Schedules the provided training code to execute immediately
/// </summary>
/// <param name="trainingCode">The training code to be invoked</param>
[DocumentationAttribute(MachineLearning)]
[DocumentationAttribute(ScheduledEvents)]
public ScheduledEvent Train(PyObject trainingCode)
{
return Schedule.TrainingNow(trainingCode);
@@ -1194,6 +1266,8 @@ namespace QuantConnect.Algorithm
/// <param name="dateRule">Specifies what dates the event should run</param>
/// <param name="timeRule">Specifies the times on those dates the event should run</param>
/// <param name="trainingCode">The training code to be invoked</param>
[DocumentationAttribute(MachineLearning)]
[DocumentationAttribute(ScheduledEvents)]
public ScheduledEvent Train(IDateRule dateRule, ITimeRule timeRule, PyObject trainingCode)
{
return Schedule.Training(dateRule, timeRule, trainingCode);
@@ -1207,6 +1281,7 @@ namespace QuantConnect.Algorithm
/// <param name="tickType">The tick type of subscription used as data source for consolidator. Specify null to use first subscription found.</param>
/// <param name="handler">Data handler receives new consolidated data when generated</param>
/// <returns>A new consolidator matching the requested parameters with the handler already registered</returns>
[DocumentationAttribute(ConsolidatingData)]
private IDataConsolidator Consolidate(Symbol symbol, Func<DateTime, CalendarInfo> calendar, TickType? tickType, PyObject handler)
{
// resolve consolidator input subscription

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -33,6 +33,7 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Transaction Manager - Process transaction fills and order management.
/// </summary>
[DocumentationAttribute(TradingAndOrders)]
public SecurityTransactionManager Transactions { get; set; }
/// <summary>
@@ -42,6 +43,7 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">int Quantity of the asset to trade</param>
/// <seealso cref="Buy(Symbol, double)"/>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Buy(Symbol symbol, int quantity)
{
return Order(symbol, (decimal)Math.Abs(quantity));
@@ -54,6 +56,7 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">double Quantity of the asset to trade</param>
/// <seealso cref="Buy(Symbol, decimal)"/>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Buy(Symbol symbol, double quantity)
{
return Order(symbol, Math.Abs(quantity).SafeDecimalCast());
@@ -66,6 +69,7 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">decimal Quantity of the asset to trade</param>
/// <seealso cref="Order(Symbol, int)"/>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Buy(Symbol symbol, decimal quantity)
{
return Order(symbol, Math.Abs(quantity));
@@ -78,6 +82,7 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">float Quantity of the asset to trade</param>
/// <seealso cref="Buy(Symbol, decimal)"/>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Buy(Symbol symbol, float quantity)
{
return Order(symbol, (decimal)Math.Abs(quantity));
@@ -91,6 +96,7 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">int Quantity of the asset to trade</param>
/// <seealso cref="Sell(Symbol, decimal)"/>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Sell(Symbol symbol, int quantity)
{
return Order(symbol, (decimal)Math.Abs(quantity) * -1);
@@ -102,6 +108,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">String symbol to sell</param>
/// <param name="quantity">Quantity to order</param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Sell(Symbol symbol, double quantity)
{
return Order(symbol, Math.Abs(quantity).SafeDecimalCast() * -1m);
@@ -113,6 +120,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">String symbol</param>
/// <param name="quantity">Quantity to sell</param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Sell(Symbol symbol, float quantity)
{
return Order(symbol, (decimal)Math.Abs(quantity) * -1m);
@@ -124,6 +132,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">String symbol to sell</param>
/// <param name="quantity">Quantity to sell</param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Sell(Symbol symbol, decimal quantity)
{
return Order(symbol, Math.Abs(quantity) * -1);
@@ -136,6 +145,7 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity to order</param>
/// <seealso cref="Order(Symbol, decimal)"/>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Order(Symbol symbol, double quantity)
{
return Order(symbol, quantity.SafeDecimalCast());
@@ -147,6 +157,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">Symbol to order</param>
/// <param name="quantity">Quantity to order</param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Order(Symbol symbol, int quantity)
{
return MarketOrder(symbol, (decimal)quantity);
@@ -158,6 +169,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">Symbol to order</param>
/// <param name="quantity">Quantity to order</param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Order(Symbol symbol, decimal quantity)
{
return MarketOrder(symbol, quantity);
@@ -173,6 +185,7 @@ namespace QuantConnect.Algorithm
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
/// <seealso cref="MarketOrder(Symbol, decimal, bool, string)"/>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Order(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOrder(symbol, quantity, asynchronous, tag, orderProperties);
@@ -187,6 +200,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket MarketOrder(Symbol symbol, int quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOrder(symbol, (decimal)quantity, asynchronous, tag, orderProperties);
@@ -201,6 +215,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket MarketOrder(Symbol symbol, double quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOrder(symbol, quantity.SafeDecimalCast(), asynchronous, tag, orderProperties);
@@ -215,6 +230,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket MarketOrder(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
@@ -230,6 +246,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket MarketOrder(Security security, decimal quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
// check the exchange is open before sending a market order, if it's not open
@@ -284,6 +301,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket MarketOnOpenOrder(Symbol symbol, double quantity, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOnOpenOrder(symbol, quantity.SafeDecimalCast(), tag, orderProperties);
@@ -297,6 +315,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket MarketOnOpenOrder(Symbol symbol, int quantity, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOnOpenOrder(symbol, (decimal)quantity, tag, orderProperties);
@@ -310,6 +329,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket MarketOnOpenOrder(Symbol symbol, decimal quantity, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
@@ -331,6 +351,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket MarketOnCloseOrder(Symbol symbol, int quantity, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOnCloseOrder(symbol, (decimal)quantity, tag, orderProperties);
@@ -344,6 +365,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket MarketOnCloseOrder(Symbol symbol, double quantity, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOnCloseOrder(symbol, quantity.SafeDecimalCast(), tag, orderProperties);
@@ -357,6 +379,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket MarketOnCloseOrder(Symbol symbol, decimal quantity, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
@@ -379,6 +402,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">String tag for the order (optional)</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket LimitOrder(Symbol symbol, int quantity, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return LimitOrder(symbol, (decimal)quantity, limitPrice, tag, orderProperties);
@@ -393,6 +417,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">String tag for the order (optional)</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket LimitOrder(Symbol symbol, double quantity, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return LimitOrder(symbol, quantity.SafeDecimalCast(), limitPrice, tag, orderProperties);
@@ -407,6 +432,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">String tag for the order (optional)</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket LimitOrder(Symbol symbol, decimal quantity, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
@@ -429,6 +455,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Optional string data tag for the order</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket StopMarketOrder(Symbol symbol, int quantity, decimal stopPrice, string tag = "", IOrderProperties orderProperties = null)
{
return StopMarketOrder(symbol, (decimal)quantity, stopPrice, tag, orderProperties);
@@ -443,6 +470,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Optional string data tag for the order</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket StopMarketOrder(Symbol symbol, double quantity, decimal stopPrice, string tag = "", IOrderProperties orderProperties = null)
{
return StopMarketOrder(symbol, quantity.SafeDecimalCast(), stopPrice, tag, orderProperties);
@@ -457,6 +485,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Optional string data tag for the order</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket StopMarketOrder(Symbol symbol, decimal quantity, decimal stopPrice, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
@@ -480,6 +509,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">String tag for the order (optional)</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket StopLimitOrder(Symbol symbol, int quantity, decimal stopPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return StopLimitOrder(symbol, (decimal)quantity, stopPrice, limitPrice, tag, orderProperties);
@@ -495,6 +525,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">String tag for the order (optional)</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket StopLimitOrder(Symbol symbol, double quantity, decimal stopPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return StopLimitOrder(symbol, quantity.SafeDecimalCast(), stopPrice, limitPrice, tag, orderProperties);
@@ -510,6 +541,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">String tag for the order (optional)</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket StopLimitOrder(Symbol symbol, decimal quantity, decimal stopPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
@@ -534,6 +566,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">String tag for the order (optional)</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket LimitIfTouchedOrder(Symbol symbol, int quantity, decimal triggerPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return LimitIfTouchedOrder(symbol, (decimal)quantity, triggerPrice, limitPrice, tag, orderProperties);
@@ -549,6 +582,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">String tag for the order (optional)</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket LimitIfTouchedOrder(Symbol symbol, double quantity, decimal triggerPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return LimitIfTouchedOrder(symbol, quantity.SafeDecimalCast(), triggerPrice, limitPrice, tag, orderProperties);
@@ -564,6 +598,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">String tag for the order (optional)</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket LimitIfTouchedOrder(Symbol symbol, decimal quantity, decimal triggerPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
@@ -587,6 +622,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">String tag for the order (optional)</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket ExerciseOption(Symbol optionSymbol, int quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
var option = (Option) Securities[optionSymbol];
@@ -629,6 +665,7 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity of the strategy to trade</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>Sequence of order tickets</returns>
[DocumentationAttribute(TradingAndOrders)]
public IEnumerable<OrderTicket> Buy(OptionStrategy strategy, int quantity, IOrderProperties orderProperties = null)
{
return Order(strategy, Math.Abs(quantity), orderProperties);
@@ -641,6 +678,7 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity of the strategy to trade</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>Sequence of order tickets</returns>
[DocumentationAttribute(TradingAndOrders)]
public IEnumerable<OrderTicket> Sell(OptionStrategy strategy, int quantity, IOrderProperties orderProperties = null)
{
return Order(strategy, Math.Abs(quantity) * -1, orderProperties);
@@ -653,6 +691,7 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity of the strategy to trade</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>Sequence of order tickets</returns>
[DocumentationAttribute(TradingAndOrders)]
public IEnumerable<OrderTicket> Order(OptionStrategy strategy, int quantity, IOrderProperties orderProperties = null)
{
return GenerateOrders(strategy, quantity, orderProperties);
@@ -925,6 +964,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Custom tag to know who is calling this.</param>
/// <returns>Array of order ids for liquidated symbols</returns>
/// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
[DocumentationAttribute(TradingAndOrders)]
public List<int> Liquidate(Symbol symbolToLiquidate = null, string tag = "Liquidated")
{
var orderIdList = new List<int>();
@@ -997,6 +1037,7 @@ namespace QuantConnect.Algorithm
/// Maximum number of orders for the algorithm
/// </summary>
/// <param name="max"></param>
[DocumentationAttribute(TradingAndOrders)]
public void SetMaximumOrders(int max)
{
if (!_locked)
@@ -1015,6 +1056,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Tag the order with a short string.</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
[DocumentationAttribute(TradingAndOrders)]
public void SetHoldings(List<PortfolioTarget> targets, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
foreach (var portfolioTarget in targets
@@ -1035,6 +1077,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Tag the order with a short string.</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
[DocumentationAttribute(TradingAndOrders)]
public void SetHoldings(Symbol symbol, double percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
SetHoldings(symbol, percentage.SafeDecimalCast(), liquidateExistingHoldings, tag, orderProperties);
@@ -1049,6 +1092,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Tag the order with a short string.</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
[DocumentationAttribute(TradingAndOrders)]
public void SetHoldings(Symbol symbol, float percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, orderProperties);
@@ -1063,6 +1107,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Tag the order with a short string.</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
[DocumentationAttribute(TradingAndOrders)]
public void SetHoldings(Symbol symbol, int percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, orderProperties);
@@ -1080,6 +1125,7 @@ namespace QuantConnect.Algorithm
/// <param name="tag">Tag the order with a short string.</param>
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
[DocumentationAttribute(TradingAndOrders)]
public void SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
SetHoldingsImpl(symbol, CalculateOrderQuantity(symbol, percentage), liquidateExistingHoldings, tag, orderProperties);
@@ -1142,6 +1188,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">Security object we're asking for</param>
/// <param name="target">Target percentage holdings</param>
/// <returns>Order quantity to achieve this percentage</returns>
[DocumentationAttribute(TradingAndOrders)]
public decimal CalculateOrderQuantity(Symbol symbol, double target)
{
return CalculateOrderQuantity(symbol, target.SafeDecimalCast());
@@ -1155,6 +1202,7 @@ namespace QuantConnect.Algorithm
/// if you have 2x leverage and request 100% holdings, it will utilize half of the
/// available margin</param>
/// <returns>Order quantity to achieve this percentage</returns>
[DocumentationAttribute(TradingAndOrders)]
public decimal CalculateOrderQuantity(Symbol symbol, decimal target)
{
var percent = PortfolioTarget.Percent(this, symbol, target, true);
@@ -1178,6 +1226,7 @@ namespace QuantConnect.Algorithm
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
[Obsolete("This Order method has been made obsolete, use Order(string, int, bool, string) method instead. Calls to the obsolete method will only generate market orders.")]
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Order(Symbol symbol, int quantity, OrderType type, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
return Order(symbol, quantity, asynchronous, tag, orderProperties);
@@ -1191,6 +1240,7 @@ namespace QuantConnect.Algorithm
/// <param name="type">The order type</param>
/// <returns>The order ticket instance.</returns>
[Obsolete("This Order method has been made obsolete, use the specialized Order helper methods instead. Calls to the obsolete method will only generate market orders.")]
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Order(Symbol symbol, decimal quantity, OrderType type)
{
return Order(symbol, quantity);
@@ -1204,6 +1254,7 @@ namespace QuantConnect.Algorithm
/// <param name="type">The order type</param>
/// <returns>The order ticket instance.</returns>
[Obsolete("This Order method has been made obsolete, use the specialized Order helper methods instead. Calls to the obsolete method will only generate market orders.")]
[DocumentationAttribute(TradingAndOrders)]
public OrderTicket Order(Symbol symbol, int quantity, OrderType type)
{
return Order(symbol, (decimal)quantity);
@@ -1214,6 +1265,8 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="symbol">The symbol</param>
/// <returns>True if the exchange is considered open at the current time, false otherwise</returns>
[DocumentationAttribute(TradingAndOrders)]
[DocumentationAttribute(SecuritiesAndPortfolio)]
public bool IsMarketOpen(Symbol symbol)
{
var exchangeHours = MarketHoursDatabase

View File

@@ -16,13 +16,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NodaTime;
using QuantConnect.Algorithm.Selection;
using QuantConnect.Data;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
using QuantConnect.Util;
namespace QuantConnect.Algorithm
@@ -43,6 +44,7 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Gets universe manager which holds universes keyed by their symbol
/// </summary>
[DocumentationAttribute(Universes)]
public UniverseManager UniverseManager
{
get;
@@ -52,6 +54,7 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Gets the universe settings to be used when adding securities via universe selection
/// </summary>
[DocumentationAttribute(Universes)]
public UniverseSettings UniverseSettings
{
get;
@@ -62,6 +65,7 @@ namespace QuantConnect.Algorithm
/// Invoked at the end of every time step. This allows the algorithm
/// to process events before advancing to the next time step.
/// </summary>
[DocumentationAttribute(HandlingData)]
public void OnEndOfTimeStep()
{
if (_pendingUniverseAdditions.Count + _pendingUserDefinedUniverseSecurityAdditions.Count == 0)
@@ -186,6 +190,7 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Gets a helper that provides pre-defined universe definitions, such as top dollar volume
/// </summary>
[DocumentationAttribute(Universes)]
public UniverseDefinitions Universe
{
get;
@@ -196,6 +201,7 @@ namespace QuantConnect.Algorithm
/// Adds the universe to the algorithm
/// </summary>
/// <param name="universe">The universe to be added</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(Universe universe)
{
// The universe will be added at the end of time step, same as the AddData user defined universes.
@@ -213,6 +219,7 @@ namespace QuantConnect.Algorithm
/// <typeparam name="T">The data type</typeparam>
/// <param name="name">A unique name for this universe</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(string name, Func<IEnumerable<T>, IEnumerable<Symbol>> selector)
{
return AddUniverse(SecurityType.Equity, name, Resolution.Daily, Market.USA, UniverseSettings, selector);
@@ -226,6 +233,7 @@ namespace QuantConnect.Algorithm
/// <typeparam name="T">The data type</typeparam>
/// <param name="name">A unique name for this universe</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(string name, Func<IEnumerable<T>, IEnumerable<string>> selector)
{
return AddUniverse(SecurityType.Equity, name, Resolution.Daily, Market.USA, UniverseSettings, selector);
@@ -240,6 +248,7 @@ namespace QuantConnect.Algorithm
/// <param name="name">A unique name for this universe</param>
/// <param name="universeSettings">The settings used for securities added by this universe</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(string name, UniverseSettings universeSettings, Func<IEnumerable<T>, IEnumerable<Symbol>> selector)
{
return AddUniverse(SecurityType.Equity, name, Resolution.Daily, Market.USA, universeSettings, selector);
@@ -254,6 +263,7 @@ namespace QuantConnect.Algorithm
/// <param name="name">A unique name for this universe</param>
/// <param name="universeSettings">The settings used for securities added by this universe</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(string name, UniverseSettings universeSettings, Func<IEnumerable<T>, IEnumerable<string>> selector)
{
return AddUniverse(SecurityType.Equity, name, Resolution.Daily, Market.USA, universeSettings, selector);
@@ -268,6 +278,7 @@ namespace QuantConnect.Algorithm
/// <param name="name">A unique name for this universe</param>
/// <param name="resolution">The epected resolution of the universe data</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(string name, Resolution resolution, Func<IEnumerable<T>, IEnumerable<Symbol>> selector)
{
return AddUniverse(SecurityType.Equity, name, resolution, Market.USA, UniverseSettings, selector);
@@ -282,6 +293,7 @@ namespace QuantConnect.Algorithm
/// <param name="name">A unique name for this universe</param>
/// <param name="resolution">The epected resolution of the universe data</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(string name, Resolution resolution, Func<IEnumerable<T>, IEnumerable<string>> selector)
{
return AddUniverse(SecurityType.Equity, name, resolution, Market.USA, UniverseSettings, selector);
@@ -297,6 +309,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The epected resolution of the universe data</param>
/// <param name="universeSettings">The settings used for securities added by this universe</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(string name, Resolution resolution, UniverseSettings universeSettings, Func<IEnumerable<T>, IEnumerable<Symbol>> selector)
{
return AddUniverse(SecurityType.Equity, name, resolution, Market.USA, universeSettings, selector);
@@ -312,6 +325,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The epected resolution of the universe data</param>
/// <param name="universeSettings">The settings used for securities added by this universe</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(string name, Resolution resolution, UniverseSettings universeSettings, Func<IEnumerable<T>, IEnumerable<string>> selector)
{
return AddUniverse(SecurityType.Equity, name, resolution, Market.USA, universeSettings, selector);
@@ -327,6 +341,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The epected resolution of the universe data</param>
/// <param name="market">The market for selected symbols</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(SecurityType securityType, string name, Resolution resolution, string market, Func<IEnumerable<T>, IEnumerable<Symbol>> selector)
{
return AddUniverse(securityType, name, resolution, market, UniverseSettings, selector);
@@ -342,6 +357,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">The epected resolution of the universe data</param>
/// <param name="market">The market for selected symbols</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(SecurityType securityType, string name, Resolution resolution, string market, Func<IEnumerable<T>, IEnumerable<string>> selector)
{
return AddUniverse(securityType, name, resolution, market, UniverseSettings, selector);
@@ -357,6 +373,7 @@ namespace QuantConnect.Algorithm
/// <param name="market">The market for selected symbols</param>
/// <param name="universeSettings">The subscription settings to use for newly created subscriptions</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, Func<IEnumerable<T>, IEnumerable<Symbol>> selector)
{
var marketHoursDbEntry = MarketHoursDatabase.GetEntry(market, name, securityType);
@@ -377,6 +394,7 @@ namespace QuantConnect.Algorithm
/// <param name="market">The market for selected symbols</param>
/// <param name="universeSettings">The subscription settings to use for newly created subscriptions</param>
/// <param name="selector">Function delegate that performs selection on the universe data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse<T>(SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, Func<IEnumerable<T>, IEnumerable<string>> selector)
{
var marketHoursDbEntry = MarketHoursDatabase.GetEntry(market, name, securityType);
@@ -394,6 +412,7 @@ namespace QuantConnect.Algorithm
/// will be executed on day changes in the NewYork time zone (<see cref="TimeZones.NewYork"/>
/// </summary>
/// <param name="selector">Defines an initial coarse selection</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(Func<IEnumerable<CoarseFundamental>, IEnumerable<Symbol>> selector)
{
return AddUniverse(new CoarseFundamentalUniverse(UniverseSettings, selector));
@@ -405,6 +424,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="coarseSelector">Defines an initial coarse selection</param>
/// <param name="fineSelector">Defines a more detailed selection with access to more data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(Func<IEnumerable<CoarseFundamental>, IEnumerable<Symbol>> coarseSelector, Func<IEnumerable<FineFundamental>, IEnumerable<Symbol>> fineSelector)
{
var coarse = new CoarseFundamentalUniverse(UniverseSettings, coarseSelector);
@@ -418,6 +438,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="universe">The universe to be filtered with fine fundamental selection</param>
/// <param name="fineSelector">Defines a more detailed selection with access to more data</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(Universe universe, Func<IEnumerable<FineFundamental>, IEnumerable<Symbol>> fineSelector)
{
return AddUniverse(new FineFundamentalFilteredUniverse(universe, fineSelector));
@@ -429,6 +450,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="name">A unique name for this universe</param>
/// <param name="selector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(string name, Func<DateTime, IEnumerable<string>> selector)
{
return AddUniverse(SecurityType.Equity, name, Resolution.Daily, Market.USA, UniverseSettings, selector);
@@ -441,6 +463,7 @@ namespace QuantConnect.Algorithm
/// <param name="name">A unique name for this universe</param>
/// <param name="resolution">The resolution this universe should be triggered on</param>
/// <param name="selector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(string name, Resolution resolution, Func<DateTime, IEnumerable<string>> selector)
{
return AddUniverse(SecurityType.Equity, name, resolution, Market.USA, UniverseSettings, selector);
@@ -455,6 +478,7 @@ namespace QuantConnect.Algorithm
/// <param name="market">The market of the universe</param>
/// <param name="universeSettings">The subscription settings used for securities added from this universe</param>
/// <param name="selector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
[DocumentationAttribute(Universes)]
public Universe AddUniverse(SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, Func<DateTime, IEnumerable<string>> selector)
{
var marketHoursDbEntry = MarketHoursDatabase.GetEntry(market, name, securityType);
@@ -472,6 +496,7 @@ namespace QuantConnect.Algorithm
/// <param name="underlyingSymbol">Underlying Symbol to add as an option. For Futures, the option chain constructed will be per-contract, as long as a canonical Symbol is provided.</param>
/// <param name="optionFilter">User-defined filter used to select the options we want out of the option chain provided.</param>
/// <exception cref="InvalidOperationException">The underlying Symbol's universe is not found.</exception>
[DocumentationAttribute(Universes)]
public void AddUniverseOptions(Symbol underlyingSymbol, Func<OptionFilterUniverse, OptionFilterUniverse> optionFilter)
{
// We need to load the universe associated with the provided Symbol and provide that universe to the option filter universe.
@@ -507,6 +532,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="universe">The universe we want to chain an option universe selection model too</param>
/// <param name="optionFilter">The option filter universe to use</param>
[DocumentationAttribute(Universes)]
public void AddUniverseOptions(Universe universe, Func<OptionFilterUniverse, OptionFilterUniverse> optionFilter)
{
AddUniverseSelection(new OptionChainedUniverseSelectionModel(universe, optionFilter));
@@ -557,14 +583,15 @@ namespace QuantConnect.Algorithm
{
// create a new universe, these subscription settings don't currently get used
// since universe selection proper is never invoked on this type of universe
var uconfig = new SubscriptionDataConfig(subscription, symbol: universeSymbol, isInternalFeed: true, fillForward: false);
var uconfig = new SubscriptionDataConfig(subscription, symbol: universeSymbol, isInternalFeed: true, fillForward: false,
exchangeTimeZone: DateTimeZone.Utc,
dataTimeZone: DateTimeZone.Utc);
if (security.Type == SecurityType.Base)
{
// set entry in market hours database for the universe subscription to match the custom data
var symbolString = MarketHoursDatabase.GetDatabaseSymbolKey(uconfig.Symbol);
MarketHoursDatabase.SetEntry(uconfig.Market, symbolString, uconfig.SecurityType, security.Exchange.Hours, uconfig.DataTimeZone);
}
// this is the universe symbol, has no real entry in the mhdb, will default to market and security type
// set entry in market hours database for the universe subscription to match the config
var symbolString = MarketHoursDatabase.GetDatabaseSymbolKey(uconfig.Symbol);
MarketHoursDatabase.SetEntry(uconfig.Market, symbolString, uconfig.SecurityType,
SecurityExchangeHours.AlwaysOpen(uconfig.ExchangeTimeZone), uconfig.DataTimeZone);
universe = new UserDefinedUniverse(uconfig,
new UniverseSettings(
@@ -593,7 +620,7 @@ namespace QuantConnect.Algorithm
else
{
// should never happen, someone would need to add a non-user defined universe with this symbol
throw new Exception("Expected universe with symbol '" + universeSymbol.Value + "' to be of type UserDefinedUniverse.");
throw new Exception($"Expected universe with symbol '{universeSymbol.Value}' to be of type {nameof(UserDefinedUniverse)} but was {universe.GetType().Name}.");
}
return security;

File diff suppressed because it is too large Load Diff

View File

@@ -21,10 +21,14 @@ using System.Net;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using RestSharp.Extensions;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
using QuantConnect.Optimizer.Objectives;
using QuantConnect.Optimizer.Parameters;
using QuantConnect.Orders;
using RestSharp;
using QuantConnect.Statistics;
using QuantConnect.Util;
namespace QuantConnect.Api
@@ -1184,6 +1188,220 @@ namespace QuantConnect.Api
return response.Organization;
}
/// <summary>
/// Estimate optimization with the specified parameters via QuantConnect.com API
/// </summary>
/// <param name="projectId">Project ID of the project the optimization belongs to</param>
/// <param name="name">Name of the optimization</param>
/// <param name="target">Target of the optimization, see examples in <see cref="PortfolioStatistics"/></param>
/// <param name="targetTo">Target extremum of the optimization, for example "max" or "min"</param>
/// <param name="targetValue">Optimization target value</param>
/// <param name="strategy">Optimization strategy, <see cref="GridSearchOptimizationStrategy"/></param>
/// <param name="compileId">Optimization compile ID</param>
/// <param name="parameters">Optimization parameters</param>
/// <param name="constraints">Optimization constraints</param>
/// <returns>Estimate object from the API.</returns>
public Estimate EstimateOptimization(
int projectId,
string name,
string target,
string targetTo,
decimal? targetValue,
string strategy,
string compileId,
HashSet<OptimizationParameter> parameters,
IReadOnlyList<Constraint> constraints)
{
var request = new RestRequest("optimizations/estimate", Method.POST)
{
RequestFormat = DataFormat.Json
};
request.AddParameter("application/json", JsonConvert.SerializeObject(new
{
projectId,
name,
target,
targetTo,
targetValue,
strategy,
compileId,
parameters,
constraints
}), ParameterType.RequestBody);
ApiConnection.TryRequest(request, out EstimateResponseWrapper response);
return response.Estimate;
}
/// <summary>
/// Create an optimization with the specified parameters via QuantConnect.com API
/// </summary>
/// <param name="projectId">Project ID of the project the optimization belongs to</param>
/// <param name="name">Name of the optimization</param>
/// <param name="target">Target of the optimization, see examples in <see cref="PortfolioStatistics"/></param>
/// <param name="targetTo">Target extremum of the optimization, for example "max" or "min"</param>
/// <param name="targetValue">Optimization target value</param>
/// <param name="strategy">Optimization strategy, <see cref="GridSearchOptimizationStrategy"/></param>
/// <param name="compileId">Optimization compile ID</param>
/// <param name="parameters">Optimization parameters</param>
/// <param name="constraints">Optimization constraints</param>
/// <param name="estimatedCost">Estimated cost for optimization</param>
/// <param name="nodeType">Optimization node type <see cref="OptimizationNodes"/></param>
/// <param name="parallelNodes">Number of parallel nodes for optimization</param>
/// <returns>BaseOptimization object from the API.</returns>
public BaseOptimization CreateOptimization(
int projectId,
string name,
string target,
string targetTo,
decimal? targetValue,
string strategy,
string compileId,
HashSet<OptimizationParameter> parameters,
IReadOnlyList<Constraint> constraints,
decimal estimatedCost,
string nodeType,
int parallelNodes)
{
var request = new RestRequest("optimizations/create", Method.POST)
{
RequestFormat = DataFormat.Json
};
request.AddParameter("application/json", JsonConvert.SerializeObject(new
{
projectId,
name,
target,
targetTo,
targetValue,
strategy,
compileId,
parameters,
constraints,
estimatedCost,
nodeType,
parallelNodes
}), ParameterType.RequestBody);
ApiConnection.TryRequest(request, out OptimizationList result);
return result.Optimizations.FirstOrDefault();
}
/// <summary>
/// List all the optimizations for a project
/// </summary>
/// <param name="projectId">Project id we'd like to get a list of optimizations for</param>
/// <returns>A list of BaseOptimization objects, <see cref="BaseOptimization"/></returns>
public List<BaseOptimization> ListOptimizations(int projectId)
{
var request = new RestRequest("optimizations/list", Method.POST)
{
RequestFormat = DataFormat.Json
};
request.AddParameter("application/json", JsonConvert.SerializeObject(new
{
projectId,
}), ParameterType.RequestBody);
ApiConnection.TryRequest(request, out OptimizationList result);
return result.Optimizations;
}
/// <summary>
/// Read an optimization
/// </summary>
/// <param name="optimizationId">Optimization id for the optimization we want to read</param>
/// <returns><see cref="Optimization"/></returns>
public Optimization ReadOptimization(string optimizationId)
{
var request = new RestRequest("optimizations/read", Method.POST)
{
RequestFormat = DataFormat.Json
};
request.AddParameter("application/json", JsonConvert.SerializeObject(new
{
optimizationId
}), ParameterType.RequestBody);
ApiConnection.TryRequest(request, out OptimizationResponseWrapper response);
return response.Optimization;
}
/// <summary>
/// Abort an optimization
/// </summary>
/// <param name="optimizationId">Optimization id for the optimization we want to abort</param>
/// <returns><see cref="RestResponse"/></returns>
public RestResponse AbortOptimization(string optimizationId)
{
var request = new RestRequest("optimizations/abort", Method.POST)
{
RequestFormat = DataFormat.Json
};
request.AddParameter("application/json", JsonConvert.SerializeObject(new
{
optimizationId
}), ParameterType.RequestBody);
ApiConnection.TryRequest(request, out RestResponse result);
return result;
}
/// <summary>
/// Update an optimization
/// </summary>
/// <param name="optimizationId">Optimization id we want to update</param>
/// <param name="name">Name we'd like to assign to the optimization</param>
/// <returns><see cref="RestResponse"/></returns>
public RestResponse UpdateOptimization(string optimizationId, string name = null)
{
var request = new RestRequest("optimizations/update", Method.POST)
{
RequestFormat = DataFormat.Json
};
var obj = new JObject
{
{ "optimizationId", optimizationId }
};
if (name.HasValue())
{
obj.Add("name", name);
}
request.AddParameter("application/json", JsonConvert.SerializeObject(obj), ParameterType.RequestBody);
ApiConnection.TryRequest(request, out RestResponse result);
return result;
}
/// <summary>
/// Delete an optimization
/// </summary>
/// <param name="optimizationId">Optimization id for the optimization we want to delete</param>
/// <returns><see cref="RestResponse"/></returns>
public RestResponse DeleteOptimization(string optimizationId)
{
var request = new RestRequest("optimizations/delete", Method.POST)
{
RequestFormat = DataFormat.Json
};
request.AddParameter("application/json", JsonConvert.SerializeObject(new
{
optimizationId
}), ParameterType.RequestBody);
ApiConnection.TryRequest(request, out RestResponse result);
return result;
}
/// <summary>
/// Helper method to normalize path for api data requests
/// </summary>

View File

@@ -34,7 +34,6 @@
<Message Text="SelectedOptimization $(SelectedOptimization)" Importance="high" />
</Target>
<ItemGroup>
<PackageReference Include="DotNetZip" Version="1.13.3" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -255,7 +255,7 @@ namespace QuantConnect.Brokerages.Backtesting
var stillNeedsScan = false;
// process each pending order to produce fills/fire events
foreach (var kvp in _pending.OrderBy(x => x.Key))
foreach (var kvp in _pending.OrderBySafe(x => x.Key))
{
var order = kvp.Value;
if (order == null)

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -33,52 +33,61 @@ namespace QuantConnect.Brokerages
{
private const int ConnectionTimeout = 30000;
/// <summary>
/// True if the current brokerage is already initialized
/// </summary>
protected bool IsInitialized { get; set; }
/// <summary>
/// The websockets client instance
/// </summary>
protected readonly IWebSocket WebSocket;
protected IWebSocket WebSocket { get; set; }
/// <summary>
/// The rest client instance
/// </summary>
protected readonly IRestClient RestClient;
protected IRestClient RestClient { get; set; }
/// <summary>
/// standard json parsing settings
/// </summary>
protected readonly JsonSerializerSettings JsonSettings;
protected JsonSerializerSettings JsonSettings { get; set; }
/// <summary>
/// A list of currently active orders
/// </summary>
public readonly ConcurrentDictionary<int, Orders.Order> CachedOrderIDs;
public ConcurrentDictionary<int, Orders.Order> CachedOrderIDs { get; set; }
/// <summary>
/// The api secret
/// </summary>
protected readonly string ApiSecret;
protected string ApiSecret { get; set; }
/// <summary>
/// The api key
/// </summary>
protected readonly string ApiKey;
protected string ApiKey { get; set; }
/// <summary>
/// Count subscribers for each (symbol, tickType) combination
/// </summary>
protected DataQueueHandlerSubscriptionManager SubscriptionManager;
protected DataQueueHandlerSubscriptionManager SubscriptionManager { get; set; }
/// <summary>
/// Creates an instance of a websockets brokerage
/// Initialize the instance of this class
/// </summary>
/// <param name="wssUrl">Websockets base url</param>
/// <param name="websocket">Websocket client instance</param>
/// <param name="restClient">Rest client instance</param>
/// <param name="apiKey">Brokerage api auth key</param>
/// <param name="apiSecret">Brokerage api auth secret</param>
/// <param name="name">Name of brokerage</param>
protected BaseWebsocketsBrokerage(string wssUrl, IWebSocket websocket, IRestClient restClient, string apiKey, string apiSecret, string name) : base(name)
/// <param name="wssUrl">The web socket base url</param>
/// <param name="websocket">instance of websockets client</param>
/// <param name="restClient">instance of rest client</param>
/// <param name="apiKey">api key</param>
/// <param name="apiSecret">api secret</param>
protected void Initialize(string wssUrl, IWebSocket websocket, IRestClient restClient, string apiKey, string apiSecret)
{
if (IsInitialized)
{
return;
}
IsInitialized = true;
JsonSettings = new JsonSerializerSettings { FloatParseHandling = FloatParseHandling.Decimal };
CachedOrderIDs = new ConcurrentDictionary<int, Orders.Order>();
@@ -97,6 +106,14 @@ namespace QuantConnect.Brokerages
ApiKey = apiKey;
}
/// <summary>
/// Creates an instance of a websockets brokerage
/// </summary>
/// <param name="name">Name of brokerage</param>
protected BaseWebsocketsBrokerage(string name) : base(name)
{
}
/// <summary>
/// Handles websocket received messages
/// </summary>

View File

@@ -28,7 +28,7 @@ namespace QuantConnect.Brokerages.Binance
{
public partial class BinanceBrokerage
{
private readonly IDataAggregator _aggregator;
private IDataAggregator _aggregator;
/// <summary>
/// Locking object for the Ticks list in the data queue handler

View File

@@ -13,6 +13,9 @@
* limitations under the License.
*/
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
@@ -20,14 +23,11 @@ using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Packets;
using QuantConnect.Securities;
using QuantConnect.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using QuantConnect.Configuration;
using QuantConnect.Util;
using Timer = System.Timers.Timer;
namespace QuantConnect.Brokerages.Binance
@@ -38,24 +38,31 @@ namespace QuantConnect.Brokerages.Binance
[BrokerageFactory(typeof(BinanceBrokerageFactory))]
public partial class BinanceBrokerage : BaseWebsocketsBrokerage, IDataQueueHandler
{
private readonly IAlgorithm _algorithm;
private IAlgorithm _algorithm;
private readonly SymbolPropertiesDatabaseSymbolMapper _symbolMapper = new SymbolPropertiesDatabaseSymbolMapper(Market.Binance);
// Binance allows 5 messages per second, but we still get rate limited if we send a lot of messages at that rate
// By sending 3 messages per second, evenly spaced out, we can keep sending messages without being limited
private readonly RateGate _webSocketRateLimiter = new RateGate(1, TimeSpan.FromMilliseconds(330));
private long _lastRequestId;
private LiveNodePacket _job;
private string _webSocketBaseUrl;
private readonly Timer _keepAliveTimer;
private readonly Timer _reconnectTimer;
private readonly BinanceRestApiClient _apiClient;
private readonly BrokerageConcurrentMessageHandler<WebSocketMessage> _messageHandler;
private Timer _keepAliveTimer;
private Timer _reconnectTimer;
private BinanceRestApiClient _apiClient;
private BrokerageConcurrentMessageHandler<WebSocketMessage> _messageHandler;
private const int MaximumSymbolsPerConnection = 512;
/// <summary>
/// Constructor for brokerage
/// </summary>
public BinanceBrokerage() : base("Binance")
{
}
/// <summary>
/// Constructor for brokerage
/// </summary>
@@ -67,67 +74,17 @@ namespace QuantConnect.Brokerages.Binance
/// <param name="aggregator">the aggregator for consolidating ticks</param>
/// <param name="job">The live job packet</param>
public BinanceBrokerage(string apiKey, string apiSecret, string restApiUrl, string webSocketBaseUrl, IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job)
: base(webSocketBaseUrl, new WebSocketClientWrapper(), null, apiKey, apiSecret, "Binance")
: base("Binance")
{
_job = job;
_algorithm = algorithm;
_aggregator = aggregator;
_webSocketBaseUrl = webSocketBaseUrl;
_messageHandler = new BrokerageConcurrentMessageHandler<WebSocketMessage>(OnUserMessage);
var maximumWebSocketConnections = Config.GetInt("binance-maximum-websocket-connections");
var symbolWeights = maximumWebSocketConnections > 0 ? FetchSymbolWeights() : null;
var subscriptionManager = new BrokerageMultiWebSocketSubscriptionManager(
webSocketBaseUrl,
MaximumSymbolsPerConnection,
maximumWebSocketConnections,
symbolWeights,
() => new BinanceWebSocketWrapper(null),
Subscribe,
Unsubscribe,
OnDataMessage,
new TimeSpan(23, 45, 0));
SubscriptionManager = subscriptionManager;
_apiClient = new BinanceRestApiClient(_symbolMapper,
algorithm?.Portfolio,
apiKey,
apiSecret,
restApiUrl);
_apiClient.OrderSubmit += (s, e) => OnOrderSubmit(e);
_apiClient.OrderStatusChanged += (s, e) => OnOrderEvent(e);
_apiClient.Message += (s, e) => OnMessage(e);
// User data streams will close after 60 minutes. It's recommended to send a ping about every 30 minutes.
// Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md#pingkeep-alive-a-listenkey
_keepAliveTimer = new Timer
{
// 30 minutes
Interval = 30 * 60 * 1000
};
_keepAliveTimer.Elapsed += (s, e) => _apiClient.SessionKeepAlive();
WebSocket.Open += (s, e) => { _keepAliveTimer.Start(); };
WebSocket.Closed += (s, e) => { _keepAliveTimer.Stop(); };
// A single connection to stream.binance.com is only valid for 24 hours; expect to be disconnected at the 24 hour mark
// Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#general-wss-information
_reconnectTimer = new Timer
{
// 23.5 hours
Interval = 23.5 * 60 * 60 * 1000
};
_reconnectTimer.Elapsed += (s, e) =>
{
Log.Trace("Daily websocket restart: disconnect");
Disconnect();
Log.Trace("Daily websocket restart: connect");
Connect();
};
Initialize(
wssUrl: webSocketBaseUrl,
restApiUrl: restApiUrl,
apiKey: apiKey,
apiSecret: apiSecret,
algorithm: algorithm,
aggregator: aggregator,
job: job
);
}
#region IBrokerage
@@ -209,18 +166,22 @@ namespace QuantConnect.Brokerages.Binance
case "MARKET":
order = new MarketOrder { Price = item.Price };
break;
case "LIMIT":
case "LIMIT_MAKER":
order = new LimitOrder { LimitPrice = item.Price };
break;
case "STOP_LOSS":
case "TAKE_PROFIT":
order = new StopMarketOrder { StopPrice = item.StopPrice, Price = item.Price };
break;
case "STOP_LOSS_LIMIT":
case "TAKE_PROFIT_LIMIT":
order = new StopLimitOrder { StopPrice = item.StopPrice, LimitPrice = item.Price };
break;
default:
OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Error, -1,
"BinanceBrokerage.GetOpenOrders: Unsupported order type returned from brokerage: " + item.Type));
@@ -344,7 +305,7 @@ namespace QuantConnect.Brokerages.Binance
_messageHandler.HandleNewMessage(e);
}
#endregion
#endregion IBrokerage
#region IDataQueueHandler
@@ -354,6 +315,27 @@ namespace QuantConnect.Brokerages.Binance
/// <param name="job">Job we're subscribing for</param>
public void SetJob(LiveNodePacket job)
{
var webSocketBaseUrl = job.BrokerageData["binance-websocket-url"];
var restApiUrl = job.BrokerageData["binance-api-url"];
var apiKey = job.BrokerageData["binance-api-key"];
var apiSecret = job.BrokerageData["binance-api-secret"];
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(
Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"));
Initialize(
wssUrl: webSocketBaseUrl,
restApiUrl: restApiUrl,
apiKey: apiKey,
apiSecret: apiSecret,
algorithm: null,
aggregator: aggregator,
job: job
);
if (!IsConnected)
{
Connect();
}
}
/// <summary>
@@ -366,7 +348,7 @@ namespace QuantConnect.Brokerages.Binance
{
if (!CanSubscribe(dataConfig.Symbol))
{
return Enumerable.Empty<BaseData>().GetEnumerator();
return null;
}
var enumerator = _aggregator.Add(dataConfig, newDataAvailableHandler);
@@ -393,10 +375,11 @@ namespace QuantConnect.Brokerages.Binance
private static bool CanSubscribe(Symbol symbol)
{
return !symbol.Value.Contains("UNIVERSE") &&
symbol.SecurityType == SecurityType.Crypto;
symbol.SecurityType == SecurityType.Crypto &&
symbol.ID.Market == Market.Binance;
}
#endregion
#endregion IDataQueueHandler
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
@@ -418,6 +401,85 @@ namespace QuantConnect.Brokerages.Binance
return true;
}
/// <summary>
/// Initialize the instance of this class
/// </summary>
/// <param name="wssUrl">The web socket base url</param>
/// <param name="restApiUrl">The rest api url</param>
/// <param name="apiKey">api key</param>
/// <param name="apiSecret">api secret</param>
/// <param name="algorithm">the algorithm instance is required to retrieve account type</param>
/// <param name="aggregator">the aggregator for consolidating ticks</param>
/// <param name="job">The live job packet</param>
private void Initialize(string wssUrl, string restApiUrl,string apiKey, string apiSecret,
IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job)
{
if (IsInitialized)
{
return;
}
base.Initialize(wssUrl, new WebSocketClientWrapper(), null, apiKey, apiSecret);
_job = job;
_algorithm = algorithm;
_aggregator = aggregator;
_webSocketBaseUrl = wssUrl;
_messageHandler = new BrokerageConcurrentMessageHandler<WebSocketMessage>(OnUserMessage);
var maximumWebSocketConnections = Config.GetInt("binance-maximum-websocket-connections");
var symbolWeights = maximumWebSocketConnections > 0 ? FetchSymbolWeights() : null;
var subscriptionManager = new BrokerageMultiWebSocketSubscriptionManager(
wssUrl,
MaximumSymbolsPerConnection,
maximumWebSocketConnections,
symbolWeights,
() => new BinanceWebSocketWrapper(null),
Subscribe,
Unsubscribe,
OnDataMessage,
new TimeSpan(23, 45, 0));
SubscriptionManager = subscriptionManager;
_apiClient = new BinanceRestApiClient(_symbolMapper,
algorithm?.Portfolio,
apiKey,
apiSecret,
restApiUrl);
_apiClient.OrderSubmit += (s, e) => OnOrderSubmit(e);
_apiClient.OrderStatusChanged += (s, e) => OnOrderEvent(e);
_apiClient.Message += (s, e) => OnMessage(e);
// User data streams will close after 60 minutes. It's recommended to send a ping about every 30 minutes.
// Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md#pingkeep-alive-a-listenkey
_keepAliveTimer = new Timer
{
// 30 minutes
Interval = 30 * 60 * 1000
};
_keepAliveTimer.Elapsed += (s, e) => _apiClient.SessionKeepAlive();
WebSocket.Open += (s, e) => { _keepAliveTimer.Start(); };
WebSocket.Closed += (s, e) => { _keepAliveTimer.Stop(); };
// A single connection to stream.binance.com is only valid for 24 hours; expect to be disconnected at the 24 hour mark
// Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#general-wss-information
_reconnectTimer = new Timer
{
// 23.5 hours
Interval = 23.5 * 60 * 60 * 1000
};
_reconnectTimer.Elapsed += (s, e) =>
{
Log.Trace("Daily websocket restart: disconnect");
Disconnect();
Log.Trace("Daily websocket restart: connect");
Connect();
};
}
/// <summary>
/// Subscribes to the requested symbol (using an individual streaming channel)
/// </summary>

View File

@@ -15,13 +15,16 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using QuantConnect.Brokerages.Bitfinex.Messages;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Packets;
using QuantConnect.Securities;
using QuantConnect.Securities.Crypto;
using QuantConnect.Util;
using RestSharp;
using System;
@@ -29,9 +32,6 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using QuantConnect.Brokerages.Bitfinex.Messages;
using QuantConnect.Packets;
using QuantConnect.Securities.Crypto;
using Order = QuantConnect.Orders.Order;
namespace QuantConnect.Brokerages.Bitfinex
@@ -45,26 +45,34 @@ namespace QuantConnect.Brokerages.Bitfinex
private const string RestApiUrl = "https://api.bitfinex.com";
private const string WebSocketUrl = "wss://api.bitfinex.com/ws/2";
private readonly LiveNodePacket _job;
private readonly IAlgorithm _algorithm;
private LiveNodePacket _job;
private IAlgorithm _algorithm;
private readonly RateGate _restRateLimiter = new RateGate(10, TimeSpan.FromMinutes(1));
private readonly ConcurrentDictionary<int, decimal> _fills = new ConcurrentDictionary<int, decimal>();
private readonly SymbolPropertiesDatabase _symbolPropertiesDatabase;
private readonly IDataAggregator _aggregator;
private SymbolPropertiesDatabase _symbolPropertiesDatabase;
private IDataAggregator _aggregator;
// map Bitfinex ClientOrderId -> LEAN order (only used for orders submitted in PlaceOrder, not for existing orders)
private readonly ConcurrentDictionary<long, Order> _orderMap = new ConcurrentDictionary<long, Order>();
private readonly object _clientOrderIdLocker = new object();
private long _nextClientOrderId;
// map Bitfinex currency to LEAN currency
private readonly Dictionary<string, string> _currencyMap;
private Dictionary<string, string> _currencyMap;
/// <summary>
/// Locking object for the Ticks list in the data queue handler
/// </summary>
public readonly object TickLocker = new object();
/// <summary>
/// Constructor for brokerage
/// </summary>
public BitfinexBrokerage() : base("Bitfinex")
{
}
/// <summary>
/// Constructor for brokerage
/// </summary>
@@ -91,39 +99,18 @@ namespace QuantConnect.Brokerages.Bitfinex
/// <param name="aggregator">consolidate ticks</param>
/// <param name="job">The live job packet</param>
public BitfinexBrokerage(IWebSocket websocket, IRestClient restClient, string apiKey, string apiSecret, IAlgorithm algorithm, IPriceProvider priceProvider, IDataAggregator aggregator, LiveNodePacket job)
: base(WebSocketUrl, websocket, restClient, apiKey, apiSecret, "Bitfinex")
: base("Bitfinex")
{
_job = job;
SubscriptionManager = new BrokerageMultiWebSocketSubscriptionManager(
WebSocketUrl,
MaximumSymbolsPerConnection,
0,
null,
() => new BitfinexWebSocketWrapper(null),
Subscribe,
Unsubscribe,
OnDataMessage,
TimeSpan.Zero,
_connectionRateLimiter);
_symbolPropertiesDatabase = SymbolPropertiesDatabase.FromDataFolder();
_algorithm = algorithm;
_aggregator = aggregator;
// load currency map
using (var wc = new WebClient())
{
var json = wc.DownloadString("https://api-pub.bitfinex.com/v2/conf/pub:map:currency:sym");
var rows = JsonConvert.DeserializeObject<List<List<List<string>>>>(json)[0];
_currencyMap = rows
.ToDictionary(row => row[0], row => row[1].ToUpperInvariant());
}
WebSocket.Open += (sender, args) =>
{
SubscribeAuth();
};
Initialize(
wssUrl: WebSocketUrl,
websocket: websocket,
restClient: restClient,
apiKey: apiKey,
apiSecret: apiSecret,
algorithm: algorithm,
aggregator: aggregator,
job: job
);
}
/// <summary>
@@ -169,6 +156,57 @@ namespace QuantConnect.Brokerages.Bitfinex
return true;
}
/// <summary>
/// Initialize the instance of this class
/// </summary>
/// <param name="wssUrl">The web socket base url</param>
/// <param name="websocket">instance of websockets client</param>
/// <param name="restClient">instance of rest client</param>
/// <param name="apiKey">api key</param>
/// <param name="apiSecret">api secret</param>
/// <param name="algorithm">the algorithm instance is required to retrieve account type</param>
/// <param name="aggregator">the aggregator for consolidating ticks</param>
/// <param name="job">The live job packet</param>
private void Initialize(string wssUrl, IWebSocket websocket, IRestClient restClient, string apiKey,
string apiSecret, IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job)
{
if (IsInitialized)
{
return;
}
base.Initialize(wssUrl, websocket, restClient, apiKey, apiSecret);
_job = job;
SubscriptionManager = new BrokerageMultiWebSocketSubscriptionManager(
WebSocketUrl,
MaximumSymbolsPerConnection,
0,
null,
() => new BitfinexWebSocketWrapper(null),
Subscribe,
Unsubscribe,
OnDataMessage,
TimeSpan.Zero,
_connectionRateLimiter);
_symbolPropertiesDatabase = SymbolPropertiesDatabase.FromDataFolder();
_algorithm = algorithm;
_aggregator = aggregator;
// load currency map
using (var wc = new WebClient())
{
var json = wc.DownloadString("https://api-pub.bitfinex.com/v2/conf/pub:map:currency:sym");
var rows = JsonConvert.DeserializeObject<List<List<List<string>>>>(json)[0];
_currencyMap = rows
.ToDictionary(row => row[0], row => row[1].ToUpperInvariant());
}
WebSocket.Open += (sender, args) =>
{
SubscribeAuth();
};
}
private long GetNextClientOrderId()
{
lock (_clientOrderIdLocker)

View File

@@ -14,6 +14,8 @@
*/
using Newtonsoft.Json;
using QuantConnect.Brokerages.Bitfinex.Messages;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
@@ -21,13 +23,13 @@ using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Packets;
using QuantConnect.Securities;
using QuantConnect.Securities.Crypto;
using QuantConnect.Util;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using QuantConnect.Brokerages.Bitfinex.Messages;
using QuantConnect.Securities.Crypto;
using Order = QuantConnect.Orders.Order;
namespace QuantConnect.Brokerages.Bitfinex
@@ -41,6 +43,7 @@ namespace QuantConnect.Brokerages.Bitfinex
private readonly SymbolPropertiesDatabaseSymbolMapper _symbolMapper = new SymbolPropertiesDatabaseSymbolMapper(Market.Bitfinex);
#region IBrokerage
/// <summary>
/// Checks if the websocket connection is connected or in the process of connecting
/// </summary>
@@ -427,7 +430,7 @@ namespace QuantConnect.Brokerages.Bitfinex
} while (startTimeStamp < endTimeStamp);
}
#endregion
#endregion IBrokerage
#region IDataQueueHandler
@@ -437,6 +440,26 @@ namespace QuantConnect.Brokerages.Bitfinex
/// <param name="job">Job we're subscribing for</param>
public void SetJob(LiveNodePacket job)
{
var apiKey = job.BrokerageData["bitfinex-api-key"];
var apiSecret = job.BrokerageData["bitfinex-api-secret"];
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(
Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"));
Initialize(
wssUrl: WebSocketUrl,
websocket: new WebSocketClientWrapper(),
restClient: new RestClient(RestApiUrl),
apiKey: apiKey,
apiSecret: apiSecret,
algorithm: null,
aggregator: aggregator,
job: job
);
if (!IsConnected)
{
Connect();
}
}
/// <summary>
@@ -447,11 +470,9 @@ namespace QuantConnect.Brokerages.Bitfinex
/// <returns>The new enumerator for this subscription request</returns>
public IEnumerator<BaseData> Subscribe(SubscriptionDataConfig dataConfig, EventHandler newDataAvailableHandler)
{
var symbol = dataConfig.Symbol;
if (symbol.Value.Contains("UNIVERSE") ||
!_symbolMapper.IsKnownLeanSymbol(symbol))
if (!CanSubscribe(dataConfig.Symbol))
{
return Enumerable.Empty<BaseData>().GetEnumerator();
return null;
}
var enumerator = _aggregator.Add(dataConfig, newDataAvailableHandler);
@@ -470,7 +491,7 @@ namespace QuantConnect.Brokerages.Bitfinex
_aggregator.Remove(dataConfig);
}
#endregion
#endregion IDataQueueHandler
/// <summary>
/// Event invocator for the Message event
@@ -492,5 +513,14 @@ namespace QuantConnect.Brokerages.Bitfinex
_onSubscribeEvent.Dispose();
_onUnsubscribeEvent.Dispose();
}
private bool CanSubscribe(Symbol symbol)
{
if (symbol.Value.Contains("UNIVERSE") || !_symbolMapper.IsKnownLeanSymbol(symbol))
{
return false;
}
return symbol.ID.Market == Market.Bitfinex;
}
}
}

View File

@@ -14,25 +14,25 @@
*/
using Newtonsoft.Json;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Packets;
using QuantConnect.Securities;
using QuantConnect.Util;
using RestSharp;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Threading;
using RestSharp;
using QuantConnect.Configuration;
using QuantConnect.Logging;
using QuantConnect.Orders.Fees;
using QuantConnect.Securities;
using QuantConnect.Util;
using QuantConnect.Data;
using QuantConnect.Packets;
using System.Threading.Tasks;
namespace QuantConnect.Brokerages.GDAX
{
@@ -44,40 +44,50 @@ namespace QuantConnect.Brokerages.GDAX
/// Collection of partial split messages
/// </summary>
public ConcurrentDictionary<long, GDAXFill> FillSplit { get; set; }
private readonly string _passPhrase;
private readonly IAlgorithm _algorithm;
private string _passPhrase;
private IAlgorithm _algorithm;
private readonly CancellationTokenSource _canceller = new CancellationTokenSource();
private readonly ConcurrentDictionary<Symbol, DefaultOrderBook> _orderBooks = new ConcurrentDictionary<Symbol, DefaultOrderBook>();
private readonly SymbolPropertiesDatabaseSymbolMapper _symbolMapper = new SymbolPropertiesDatabaseSymbolMapper(Market.GDAX);
private readonly bool _isDataQueueHandler;
private bool _isDataQueueHandler;
private LiveNodePacket _job;
/// <summary>
/// Data Aggregator
/// </summary>
protected readonly IDataAggregator _aggregator;
protected IDataAggregator _aggregator;
// GDAX has different rate limits for public and private endpoints
// https://docs.gdax.com/#rate-limits
internal enum GdaxEndpointType { Public, Private }
private readonly RateGate _publicEndpointRateLimiter = new RateGate(6, TimeSpan.FromSeconds(1));
private readonly RateGate _privateEndpointRateLimiter = new RateGate(10, TimeSpan.FromSeconds(1));
private readonly IPriceProvider _priceProvider;
private IPriceProvider _priceProvider;
private readonly CancellationTokenSource _ctsFillMonitor = new CancellationTokenSource();
private readonly Task _fillMonitorTask;
private Task _fillMonitorTask;
private readonly AutoResetEvent _fillMonitorResetEvent = new AutoResetEvent(false);
private readonly int _fillMonitorTimeout = Config.GetInt("gdax-fill-monitor-timeout", 500);
private readonly ConcurrentDictionary<string, PendingOrder> _pendingOrders = new ConcurrentDictionary<string, PendingOrder>();
#endregion
#endregion Declarations
/// <summary>
/// The list of websocket channels to subscribe
/// </summary>
protected virtual string[] ChannelNames { get; } = { "heartbeat" };
/// <summary>
/// Constructor for brokerage
/// </summary>
/// <param name="name">Name of brokerage</param>
public GDAXBrokerage(string name) : base(name)
{
}
/// <summary>
/// Constructor for brokerage
/// </summary>
@@ -93,18 +103,20 @@ namespace QuantConnect.Brokerages.GDAX
/// <param name="job">The live job packet</param>
public GDAXBrokerage(string wssUrl, IWebSocket websocket, IRestClient restClient, string apiKey, string apiSecret, string passPhrase, IAlgorithm algorithm,
IPriceProvider priceProvider, IDataAggregator aggregator, LiveNodePacket job)
: base(wssUrl, websocket, restClient, apiKey, apiSecret, "GDAX")
: base("GDAX")
{
_job = job;
FillSplit = new ConcurrentDictionary<long, GDAXFill>();
_passPhrase = passPhrase;
_algorithm = algorithm;
_priceProvider = priceProvider;
_aggregator = aggregator;
_isDataQueueHandler = this is GDAXDataQueueHandler;
_fillMonitorTask = Task.Factory.StartNew(FillMonitorAction, _ctsFillMonitor.Token);
Initialize(
wssUrl: wssUrl,
websocket: websocket,
restClient: restClient,
apiKey: apiKey,
apiSecret: apiSecret,
passPhrase: passPhrase,
algorithm: algorithm,
priceProvider: priceProvider,
aggregator: aggregator,
job: job
);
}
/// <summary>
@@ -167,6 +179,49 @@ namespace QuantConnect.Brokerages.GDAX
}
}
/// <summary>
/// Initialize the instance of this class
/// </summary>
/// <param name="wssUrl">The web socket base url</param>
/// <param name="websocket">instance of websockets client</param>
/// <param name="restClient">instance of rest client</param>
/// <param name="apiKey">api key</param>
/// <param name="apiSecret">api secret</param>
/// <param name="passPhrase">pass phrase</param>
/// <param name="algorithm">the algorithm instance is required to retrieve account type</param>
/// <param name="priceProvider">The price provider for missing FX conversion rates</param>
/// <param name="aggregator">the aggregator for consolidating ticks</param>
/// <param name="job">The live job packet</param>
protected void Initialize(string wssUrl, IWebSocket websocket, IRestClient restClient, string apiKey, string apiSecret,
string passPhrase, IAlgorithm algorithm, IPriceProvider priceProvider, IDataAggregator aggregator, LiveNodePacket job)
{
if (IsInitialized)
{
return;
}
base.Initialize(wssUrl, websocket, restClient, apiKey, apiSecret);
_job = job;
FillSplit = new ConcurrentDictionary<long, GDAXFill>();
_passPhrase = passPhrase;
_algorithm = algorithm;
_priceProvider = priceProvider;
_aggregator = aggregator;
_isDataQueueHandler = this is GDAXDataQueueHandler;
_fillMonitorTask = Task.Factory.StartNew(FillMonitorAction, _ctsFillMonitor.Token);
var subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager();
subscriptionManager.SubscribeImpl += (s, t) =>
{
Subscribe(s);
return true;
};
subscriptionManager.UnsubscribeImpl += (s, t) => Unsubscribe(s);
SubscriptionManager = subscriptionManager;
}
private void OnSnapshot(string data)
{
try
@@ -259,7 +314,6 @@ namespace QuantConnect.Brokerages.GDAX
orderBook.UpdateAskRow(price, size);
}
}
}
}
catch (Exception e)

View File

@@ -94,7 +94,7 @@ namespace QuantConnect.Brokerages.GDAX
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"));
IBrokerage brokerage;
if (job.DataQueueHandler.EndsWith("GDAXDataQueueHandler"))
if (job.DataQueueHandler.Contains("GDAXDataQueueHandler"))
{
var dataQueueHandler = new GDAXDataQueueHandler(job.BrokerageData["gdax-url"], webSocketClient,
restClient, job.BrokerageData["gdax-api-key"], job.BrokerageData["gdax-api-secret"],

View File

@@ -13,13 +13,14 @@
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using QuantConnect.Packets;
using QuantConnect.Util;
using RestSharp;
using System;
using System.Collections.Generic;
namespace QuantConnect.Brokerages.GDAX
{
@@ -29,6 +30,13 @@ namespace QuantConnect.Brokerages.GDAX
[BrokerageFactory(typeof(GDAXBrokerageFactory))]
public class GDAXDataQueueHandler : GDAXBrokerage, IDataQueueHandler
{
/// <summary>
/// Constructor for brokerage
/// </summary>
public GDAXDataQueueHandler() : base("GDAX")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GDAXDataQueueHandler"/> class
/// </summary>
@@ -36,15 +44,18 @@ namespace QuantConnect.Brokerages.GDAX
IPriceProvider priceProvider, IDataAggregator aggregator, LiveNodePacket job)
: base(wssUrl, websocket, restClient, apiKey, apiSecret, passPhrase, algorithm, priceProvider, aggregator, job)
{
var subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager();
subscriptionManager.SubscribeImpl += (s,t) =>
{
Subscribe(s);
return true;
};
subscriptionManager.UnsubscribeImpl += (s, t) => Unsubscribe(s);
SubscriptionManager = subscriptionManager;
Initialize(
wssUrl: wssUrl,
websocket: websocket,
restClient: restClient,
apiKey: apiKey,
apiSecret: apiSecret,
passPhrase: passPhrase,
algorithm: algorithm,
priceProvider: priceProvider,
aggregator: aggregator,
job: job
);
}
/// <summary>
@@ -62,7 +73,7 @@ namespace QuantConnect.Brokerages.GDAX
{
if (!CanSubscribe(dataConfig.Symbol))
{
return Enumerable.Empty<BaseData>().GetEnumerator();
return null;
}
var enumerator = _aggregator.Add(dataConfig, newDataAvailableHandler);
@@ -77,6 +88,34 @@ namespace QuantConnect.Brokerages.GDAX
/// <param name="job">Job we're subscribing for</param>
public void SetJob(LiveNodePacket job)
{
var wssUrl = job.BrokerageData["gdax-url"];
var restApi = job.BrokerageData["gdax-rest-api"];
var restClient = new RestClient(restApi);
var webSocketClient = new WebSocketClientWrapper();
var passPhrase = job.BrokerageData["gdax-passphrase"];
var apiKey = job.BrokerageData["gdax-api-key"];
var apiSecret = job.BrokerageData["gdax-api-secret"];
var priceProvider = new ApiPriceProvider(job.UserId, job.UserToken);
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(
Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"));
Initialize(
wssUrl: wssUrl,
websocket: webSocketClient,
restClient: restClient,
apiKey: apiKey,
apiSecret: apiSecret,
passPhrase: passPhrase,
algorithm: null,
priceProvider: priceProvider,
aggregator: aggregator,
job: job
);
if (!IsConnected)
{
Connect();
}
}
/// <summary>
@@ -102,7 +141,7 @@ namespace QuantConnect.Brokerages.GDAX
return false;
}
return true;
return symbol.ID.Market == Market.GDAX;
}
}
}

View File

@@ -13,6 +13,24 @@
* limitations under the License.
*/
using IBApi;
using NodaTime;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.IBAutomater;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Orders.TimeInForces;
using QuantConnect.Packets;
using QuantConnect.Securities;
using QuantConnect.Securities.FutureOption;
using QuantConnect.Securities.Index;
using QuantConnect.Securities.IndexOption;
using QuantConnect.Securities.Option;
using QuantConnect.Util;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -21,28 +39,10 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Packets;
using QuantConnect.Securities;
using QuantConnect.Util;
using Order = QuantConnect.Orders.Order;
using IB = QuantConnect.Brokerages.InteractiveBrokers.Client;
using IBApi;
using NodaTime;
using QuantConnect.IBAutomater;
using QuantConnect.Orders.Fees;
using QuantConnect.Orders.TimeInForces;
using QuantConnect.Securities.FutureOption;
using QuantConnect.Securities.Index;
using QuantConnect.Securities.IndexOption;
using QuantConnect.Securities.Option;
using Bar = QuantConnect.Data.Market.Bar;
using HistoryRequest = QuantConnect.Data.HistoryRequest;
using IB = QuantConnect.Brokerages.InteractiveBrokers.Client;
using Order = QuantConnect.Orders.Order;
namespace QuantConnect.Brokerages.InteractiveBrokers
{
@@ -57,28 +57,30 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
/// </summary>
public static string DefaultVersion { get; } = "985";
private readonly IBAutomater.IBAutomater _ibAutomater;
private IBAutomater.IBAutomater _ibAutomater;
// Existing orders created in TWS can *only* be cancelled/modified when connected with ClientId = 0
private const int ClientId = 0;
private const string _futuresCmeCrypto = "CMECRYPTO";
// next valid order id (or request id, or ticker id) for this client
private int _nextValidId;
private readonly object _nextValidIdLocker = new object();
private readonly int _port;
private readonly string _account;
private readonly string _host;
private readonly IAlgorithm _algorithm;
private readonly bool _loadExistingHoldings;
private readonly IOrderProvider _orderProvider;
private readonly ISecurityProvider _securityProvider;
private readonly IDataAggregator _aggregator;
private readonly IB.InteractiveBrokersClient _client;
private readonly int _ibVersion;
private readonly string _agentDescription;
private readonly EventBasedDataQueueHandlerSubscriptionManager _subscriptionManager;
private int _port;
private string _account;
private string _host;
private IAlgorithm _algorithm;
private bool _loadExistingHoldings;
private IOrderProvider _orderProvider;
private ISecurityProvider _securityProvider;
private IDataAggregator _aggregator;
private IB.InteractiveBrokersClient _client;
private int _ibVersion;
private string _agentDescription;
private EventBasedDataQueueHandlerSubscriptionManager _subscriptionManager;
private Thread _messageProcessingThread;
@@ -92,8 +94,10 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
// tracks requested order updates, so we can flag Submitted order events as updates
private readonly ConcurrentDictionary<int, int> _orderUpdates = new ConcurrentDictionary<int, int>();
// tracks executions before commission reports, map: execId -> execution
private readonly ConcurrentDictionary<string, IB.ExecutionDetailsEventArgs> _orderExecutions = new ConcurrentDictionary<string, IB.ExecutionDetailsEventArgs>();
// tracks commission reports before executions, map: execId -> commission report
private readonly ConcurrentDictionary<string, CommissionReport> _commissionReports = new ConcurrentDictionary<string, CommissionReport>();
@@ -107,7 +111,7 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
private readonly ConcurrentDictionary<string, ContractDetails> _contractDetails = new ConcurrentDictionary<string, ContractDetails>();
private readonly InteractiveBrokersSymbolMapper _symbolMapper;
private InteractiveBrokersSymbolMapper _symbolMapper;
// Prioritized list of exchanges used to find right futures contract
private readonly Dictionary<string, string> _futuresExchanges = new Dictionary<string, string>
@@ -134,11 +138,13 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
// when unsubscribing symbols immediately after subscribing IB returns an error (Can't find EId with tickerId:nnn),
// so we track subscription times to ensure symbols are not unsubscribed before a minimum time span has elapsed
private readonly Dictionary<int, DateTime> _subscriptionTimes = new Dictionary<int, DateTime>();
private readonly TimeSpan _minimumTimespanBeforeUnsubscribe = TimeSpan.FromMilliseconds(500);
private readonly bool _enableDelayedStreamingData = Config.GetBool("ib-enable-delayed-streaming-data");
private volatile bool _isDisposeCalled;
private bool _isInitialized;
/// <summary>
/// Returns true if we're currently connected to the broker
@@ -160,6 +166,13 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
return account.Contains("F");
}
/// <summary>
/// Creates a new InteractiveBrokersBrokerage using values from configuration
/// </summary>
public InteractiveBrokersBrokerage() : base("Interactive Brokers Brokerage")
{
}
/// <summary>
/// Creates a new InteractiveBrokersBrokerage using values from configuration:
/// ib-account (required)
@@ -242,78 +255,22 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
bool loadExistingHoldings = true)
: base("Interactive Brokers Brokerage")
{
_loadExistingHoldings = loadExistingHoldings;
_algorithm = algorithm;
_orderProvider = orderProvider;
_securityProvider = securityProvider;
_aggregator = aggregator;
_account = account;
_host = host;
_port = port;
_ibVersion = Convert.ToInt32(ibVersion, CultureInfo.InvariantCulture);
_agentDescription = agentDescription;
_symbolMapper = new InteractiveBrokersSymbolMapper(mapFileProvider);
_subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager();
_subscriptionManager.SubscribeImpl += (s, t) => Subscribe(s);
_subscriptionManager.UnsubscribeImpl += (s, t) => Unsubscribe(s);
Log.Trace("InteractiveBrokersBrokerage.InteractiveBrokersBrokerage(): Starting IB Automater...");
// start IB Gateway
var exportIbGatewayLogs = Config.GetBool("ib-export-ibgateway-logs");
_ibAutomater = new IBAutomater.IBAutomater(ibDirectory, ibVersion, userName, password, tradingMode, port, exportIbGatewayLogs);
_ibAutomater.OutputDataReceived += OnIbAutomaterOutputDataReceived;
_ibAutomater.ErrorDataReceived += OnIbAutomaterErrorDataReceived;
_ibAutomater.Exited += OnIbAutomaterExited;
_ibAutomater.Restarted += OnIbAutomaterRestarted;
CheckIbAutomaterError(_ibAutomater.Start(false));
Log.Trace($"InteractiveBrokersBrokerage.InteractiveBrokersBrokerage(): Host: {host}, Port: {port}, Account: {account}, AgentDescription: {agentDescription}");
_client = new IB.InteractiveBrokersClient(_signal);
// set up event handlers
_client.UpdatePortfolio += HandlePortfolioUpdates;
_client.OrderStatus += HandleOrderStatusUpdates;
_client.OpenOrder += HandleOpenOrder;
_client.OpenOrderEnd += HandleOpenOrderEnd;
_client.UpdateAccountValue += HandleUpdateAccountValue;
_client.AccountSummary += HandleAccountSummary;
_client.ManagedAccounts += HandleManagedAccounts;
_client.FamilyCodes += HandleFamilyCodes;
_client.ExecutionDetails += HandleExecutionDetails;
_client.CommissionReport += HandleCommissionReport;
_client.Error += HandleError;
_client.TickPrice += HandleTickPrice;
_client.TickSize += HandleTickSize;
_client.CurrentTimeUtc += HandleBrokerTime;
// we need to wait until we receive the next valid id from the server
_client.NextValidId += (sender, e) =>
{
lock (_nextValidIdLocker)
{
Log.Trace($"InteractiveBrokersBrokerage.HandleNextValidID(): updating nextValidId from {_nextValidId} to {e.OrderId}");
_nextValidId = e.OrderId;
_waitForNextValidId.Set();
}
};
_client.ConnectAck += (sender, e) =>
{
Log.Trace($"InteractiveBrokersBrokerage.HandleConnectAck(): API client connected [Server Version: {_client.ClientSocket.ServerVersion}].");
_connectEvent.Set();
};
_client.ConnectionClosed += (sender, e) =>
{
Log.Trace($"InteractiveBrokersBrokerage.HandleConnectionClosed(): API client disconnected [Server Version: {_client.ClientSocket.ServerVersion}].");
_connectEvent.Set();
};
Initialize(
algorithm,
orderProvider,
securityProvider,
aggregator,
mapFileProvider,
account,
host,
port,
ibDirectory,
ibVersion,
userName,
password,
tradingMode,
agentDescription = IB.AgentDescription.Individual,
loadExistingHoldings = true);
}
/// <summary>
@@ -831,6 +788,9 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
{
Log.Trace("InteractiveBrokersBrokerage.Connect(): Restoring data subscriptions...");
RestoreDataSubscriptions();
// we need to tell the DefaultBrokerageMessageHandler we are connected else he will kill us
OnMessage(BrokerageMessageEvent.Reconnected("Connect() finished successfully"));
}
else
{
@@ -955,6 +915,120 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
_messagingRateLimiter.Dispose();
}
/// <summary>
/// Initialize the instance of this class
/// </summary>
/// <param name="algorithm">The algorithm instance</param>
/// <param name="orderProvider">An instance of IOrderProvider used to fetch Order objects by brokerage ID</param>
/// <param name="securityProvider">The security provider used to give access to algorithm securities</param>
/// <param name="aggregator">consolidate ticks</param>
/// <param name="mapFileProvider">representing all the map files</param>
/// <param name="account">The Interactive Brokers account name</param>
/// <param name="host">host name or IP address of the machine where TWS is running. Leave blank to connect to the local host.</param>
/// <param name="port">must match the port specified in TWS on the Configure&gt;API&gt;Socket Port field.</param>
/// <param name="ibDirectory">The IB Gateway root directory</param>
/// <param name="ibVersion">The IB Gateway version</param>
/// <param name="userName">The login user name</param>
/// <param name="password">The login password</param>
/// <param name="tradingMode">The trading mode: 'live' or 'paper'</param>
/// <param name="agentDescription">Used for Rule 80A describes the type of trader.</param>
/// <param name="loadExistingHoldings">False will ignore existing security holdings from being loaded.</param>
private void Initialize(
IAlgorithm algorithm,
IOrderProvider orderProvider,
ISecurityProvider securityProvider,
IDataAggregator aggregator,
IMapFileProvider mapFileProvider,
string account,
string host,
int port,
string ibDirectory,
string ibVersion,
string userName,
string password,
string tradingMode,
string agentDescription = IB.AgentDescription.Individual,
bool loadExistingHoldings = true)
{
if (_isInitialized)
{
return;
}
_isInitialized = true;
_loadExistingHoldings = loadExistingHoldings;
_algorithm = algorithm;
_orderProvider = orderProvider;
_securityProvider = securityProvider;
_aggregator = aggregator;
_account = account;
_host = host;
_port = port;
_ibVersion = Convert.ToInt32(ibVersion, CultureInfo.InvariantCulture);
_agentDescription = agentDescription;
_symbolMapper = new InteractiveBrokersSymbolMapper(mapFileProvider);
_subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager();
_subscriptionManager.SubscribeImpl += (s, t) => Subscribe(s);
_subscriptionManager.UnsubscribeImpl += (s, t) => Unsubscribe(s);
Log.Trace("InteractiveBrokersBrokerage.InteractiveBrokersBrokerage(): Starting IB Automater...");
// start IB Gateway
var exportIbGatewayLogs = Config.GetBool("ib-export-ibgateway-logs");
_ibAutomater = new IBAutomater.IBAutomater(ibDirectory, ibVersion, userName, password, tradingMode, port, exportIbGatewayLogs);
_ibAutomater.OutputDataReceived += OnIbAutomaterOutputDataReceived;
_ibAutomater.ErrorDataReceived += OnIbAutomaterErrorDataReceived;
_ibAutomater.Exited += OnIbAutomaterExited;
_ibAutomater.Restarted += OnIbAutomaterRestarted;
CheckIbAutomaterError(_ibAutomater.Start(false));
Log.Trace($"InteractiveBrokersBrokerage.InteractiveBrokersBrokerage(): Host: {host}, Port: {port}, Account: {account}, AgentDescription: {agentDescription}");
_client = new IB.InteractiveBrokersClient(_signal);
// set up event handlers
_client.UpdatePortfolio += HandlePortfolioUpdates;
_client.OrderStatus += HandleOrderStatusUpdates;
_client.OpenOrder += HandleOpenOrder;
_client.OpenOrderEnd += HandleOpenOrderEnd;
_client.UpdateAccountValue += HandleUpdateAccountValue;
_client.AccountSummary += HandleAccountSummary;
_client.ManagedAccounts += HandleManagedAccounts;
_client.FamilyCodes += HandleFamilyCodes;
_client.ExecutionDetails += HandleExecutionDetails;
_client.CommissionReport += HandleCommissionReport;
_client.Error += HandleError;
_client.TickPrice += HandleTickPrice;
_client.TickSize += HandleTickSize;
_client.CurrentTimeUtc += HandleBrokerTime;
// we need to wait until we receive the next valid id from the server
_client.NextValidId += (sender, e) =>
{
lock (_nextValidIdLocker)
{
Log.Trace($"InteractiveBrokersBrokerage.HandleNextValidID(): updating nextValidId from {_nextValidId} to {e.OrderId}");
_nextValidId = e.OrderId;
_waitForNextValidId.Set();
}
};
_client.ConnectAck += (sender, e) =>
{
Log.Trace($"InteractiveBrokersBrokerage.HandleConnectAck(): API client connected [Server Version: {_client.ClientSocket.ServerVersion}].");
_connectEvent.Set();
};
_client.ConnectionClosed += (sender, e) =>
{
Log.Trace($"InteractiveBrokersBrokerage.HandleConnectionClosed(): API client disconnected [Server Version: {_client.ClientSocket.ServerVersion}].");
_connectEvent.Set();
};
}
/// <summary>
/// Places the order with InteractiveBrokers
/// </summary>
@@ -1850,7 +1924,6 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
{
// order for an account profile
ibOrder.FaProfile = orderProperties.FaProfile;
}
else if (!string.IsNullOrWhiteSpace(orderProperties.FaGroup))
{
@@ -1965,12 +2038,18 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
var securityType = ConvertSecurityType(symbol.SecurityType);
var ibSymbol = _symbolMapper.GetBrokerageSymbol(symbol);
var symbolProperties = _symbolPropertiesDatabase.GetSymbolProperties(
symbol.ID.Market,
symbol,
symbol.SecurityType,
Currencies.USD);
var contract = new Contract
{
Symbol = ibSymbol,
Exchange = exchange ?? GetSymbolExchange(symbol),
SecType = securityType,
Currency = Currencies.USD
Currency = symbolProperties.QuoteCurrency
};
if (symbol.ID.SecurityType == SecurityType.Forex)
{
@@ -2036,12 +2115,6 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
contract.LastTradeDateOrContractMonth = symbol.ID.Date.ToStringInvariant(DateFormat.EightCharacter);
contract.Exchange = GetSymbolExchange(symbol);
var symbolProperties = _symbolPropertiesDatabase.GetSymbolProperties(
symbol.ID.Market,
symbol,
symbol.SecurityType,
Currencies.USD);
contract.Multiplier = Convert.ToInt32(symbolProperties.ContractMultiplier).ToStringInvariant();
contract.IncludeExpired = includeExpired;
@@ -2072,7 +2145,7 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
{
switch (direction)
{
case OrderDirection.Buy: return IB.ActionSide.Buy;
case OrderDirection.Buy: return IB.ActionSide.Buy;
case OrderDirection.Sell: return IB.ActionSide.Sell;
case OrderDirection.Hold: return IB.ActionSide.Undefined;
default:
@@ -2087,13 +2160,13 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
{
switch (type)
{
case OrderType.Market: return IB.OrderType.Market;
case OrderType.Limit: return IB.OrderType.Limit;
case OrderType.StopMarket: return IB.OrderType.Stop;
case OrderType.StopLimit: return IB.OrderType.StopLimit;
case OrderType.LimitIfTouched: return IB.OrderType.LimitIfTouched;
case OrderType.MarketOnOpen: return IB.OrderType.Market;
case OrderType.MarketOnClose: return IB.OrderType.MarketOnClose;
case OrderType.Market: return IB.OrderType.Market;
case OrderType.Limit: return IB.OrderType.Limit;
case OrderType.StopMarket: return IB.OrderType.Stop;
case OrderType.StopLimit: return IB.OrderType.StopLimit;
case OrderType.LimitIfTouched: return IB.OrderType.LimitIfTouched;
case OrderType.MarketOnOpen: return IB.OrderType.Market;
case OrderType.MarketOnClose: return IB.OrderType.MarketOnClose;
default:
throw new InvalidEnumArgumentException(nameof(type), (int)type, typeof(OrderType));
}
@@ -2106,11 +2179,11 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
{
switch (order.OrderType)
{
case IB.OrderType.Limit: return OrderType.Limit;
case IB.OrderType.Stop: return OrderType.StopMarket;
case IB.OrderType.StopLimit: return OrderType.StopLimit;
case IB.OrderType.LimitIfTouched: return OrderType.LimitIfTouched;
case IB.OrderType.MarketOnClose: return OrderType.MarketOnClose;
case IB.OrderType.Limit: return OrderType.Limit;
case IB.OrderType.Stop: return OrderType.StopMarket;
case IB.OrderType.StopLimit: return OrderType.StopLimit;
case IB.OrderType.LimitIfTouched: return OrderType.LimitIfTouched;
case IB.OrderType.MarketOnClose: return OrderType.MarketOnClose;
case IB.OrderType.Market:
if (order.Tif == IB.TimeInForce.MarketOnOpen)
@@ -2267,7 +2340,7 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
case SecurityType.Option:
case SecurityType.IndexOption:
return IB.SecurityType.Option;
return IB.SecurityType.Option;
case SecurityType.Index:
return IB.SecurityType.Index;
@@ -2520,6 +2593,44 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
/// <param name="job">Job we're subscribing for</param>
public void SetJob(LiveNodePacket job)
{
// read values from the brokerage datas
var port = Config.GetInt("ib-port", 4001);
var host = Config.Get("ib-host", "127.0.0.1");
var twsDirectory = Config.Get("ib-tws-dir", "C:\\Jts");
var ibVersion = Config.Get("ib-version", DefaultVersion);
var account = job.BrokerageData["ib-account"];
var userId = job.BrokerageData["ib-user-name"];
var password = job.BrokerageData["ib-password"];
var tradingMode = job.BrokerageData["ib-trading-mode"];
var agentDescription = job.BrokerageData["ib-agent-description"];
var loadExistingHoldings = true;
if (job.BrokerageData.ContainsKey("load-existing-holdings"))
{
loadExistingHoldings = Convert.ToBoolean(job.BrokerageData["load-existing-holdings"]);
}
Initialize(null,
null,
null,
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager")),
Composer.Instance.GetExportedValueByTypeName<IMapFileProvider>(Config.Get("map-file-provider", "QuantConnect.Data.Auxiliary.LocalDiskMapFileProvider")),
account,
host,
port,
twsDirectory,
ibVersion,
userId,
password,
tradingMode,
agentDescription,
loadExistingHoldings);
if (!IsConnected)
{
Connect();
}
}
/// <summary>
@@ -2532,7 +2643,7 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
{
if (!CanSubscribe(dataConfig.Symbol))
{
return Enumerable.Empty<BaseData>().GetEnumerator();
return null;
}
var enumerator = _aggregator.Add(dataConfig, newDataAvailableHandler);
@@ -2811,6 +2922,7 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
case SecurityType.Equity:
// Effective in TWS version 985 and later, for US stocks the bid, ask, and last size quotes are shown in shares (not in lots).
return _ibVersion < 985 ? size * 100 : size;
default:
return size;
}
@@ -3009,7 +3121,7 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
SecType = ConvertSecurityType(symbol.SecurityType),
IncludeExpired = includeExpired,
Multiplier = Convert.ToInt32(symbolProperties.ContractMultiplier).ToStringInvariant()
};
};
Log.Trace($"InteractiveBrokersBrokerage.LookupSymbols(): Requesting symbol list for {contract.Symbol} ...");
@@ -3538,5 +3650,4 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
1100, 1101, 1102, 2103, 2104, 2105, 2106, 2107, 2108, 2119, 2157, 2158, 10197
};
}
}

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -13,11 +13,8 @@
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using NodaTime;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
@@ -25,6 +22,11 @@ using QuantConnect.Logging;
using QuantConnect.Packets;
using QuantConnect.Securities;
using QuantConnect.Securities.Forex;
using QuantConnect.Util;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using HistoryRequest = QuantConnect.Data.HistoryRequest;
using Order = QuantConnect.Orders.Order;
@@ -37,13 +39,21 @@ namespace QuantConnect.Brokerages.Oanda
public class OandaBrokerage : Brokerage, IDataQueueHandler
{
private readonly OandaSymbolMapper _symbolMapper = new OandaSymbolMapper();
private readonly OandaRestApiBase _api;
private OandaRestApiBase _api;
private bool _isInitialized;
/// <summary>
/// The maximum number of bars per historical data request
/// </summary>
public const int MaxBarsPerRequest = 5000;
/// <summary>
/// Initializes a new instance of the <see cref="OandaBrokerage"/> class.
/// </summary>
public OandaBrokerage() : base("Oanda Brokerage")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="OandaBrokerage"/> class.
/// </summary>
@@ -57,15 +67,7 @@ namespace QuantConnect.Brokerages.Oanda
public OandaBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider, IDataAggregator aggregator, Environment environment, string accessToken, string accountId, string agent = OandaRestApiBase.OandaAgentDefaultValue)
: base("Oanda Brokerage")
{
if (environment != Environment.Trade && environment != Environment.Practice)
throw new NotSupportedException("Oanda Environment not supported: " + environment);
_api = new OandaRestApiV20(_symbolMapper, orderProvider, securityProvider, aggregator, environment, accessToken, accountId, agent);
// forward events received from API
_api.OrderStatusChanged += (sender, orderEvent) => OnOrderEvent(orderEvent);
_api.AccountChanged += (sender, accountEvent) => OnAccountChanged(accountEvent);
_api.Message += (sender, messageEvent) => OnMessage(messageEvent);
Initialize(orderProvider, securityProvider, aggregator, environment, accessToken, accountId, agent = OandaRestApiBase.OandaAgentDefaultValue);
}
#region IBrokerage implementation
@@ -241,7 +243,7 @@ namespace QuantConnect.Brokerages.Oanda
}
}
#endregion
#endregion IBrokerage implementation
#region IDataQueueHandler implementation
@@ -251,6 +253,25 @@ namespace QuantConnect.Brokerages.Oanda
/// <param name="job">Job we're subscribing for</param>
public void SetJob(LiveNodePacket job)
{
Enum.TryParse(job.BrokerageData["oanda-environment"], out Environment environment);
var accessToken = job.BrokerageData["oanda-access-token"];
var accountId = job.BrokerageData["oanda-account-id"];
var agent = job.BrokerageData["oanda-agent"];
Initialize(
null,
null,
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager")),
environment,
accessToken,
accountId,
agent);
if (!IsConnected)
{
Connect();
}
_api.SetJob(job);
}
@@ -274,7 +295,7 @@ namespace QuantConnect.Brokerages.Oanda
_api.Unsubscribe(dataConfig);
}
#endregion
#endregion IDataQueueHandler implementation
/// <summary>
/// Returns a DateTime from an RFC3339 string (with microsecond resolution)
@@ -322,5 +343,34 @@ namespace QuantConnect.Brokerages.Oanda
{
return _api.DownloadQuoteBars(symbol, startTimeUtc, endTimeUtc, resolution, requestedTimeZone);
}
/// <summary>
/// Initializes a new instance of the class.
/// </summary>
/// <param name="orderProvider">The order provider.</param>
/// <param name="securityProvider">The holdings provider.</param>
/// <param name="aggregator">consolidate ticks</param>
/// <param name="environment">The Oanda environment (Trade or Practice)</param>
/// <param name="accessToken">The Oanda access token (can be the user's personal access token or the access token obtained with OAuth by QC on behalf of the user)</param>
/// <param name="accountId">The account identifier.</param>
/// <param name="agent">The Oanda agent string</param>
private void Initialize(IOrderProvider orderProvider, ISecurityProvider securityProvider, IDataAggregator aggregator,
Environment environment, string accessToken, string accountId, string agent = OandaRestApiBase.OandaAgentDefaultValue)
{
if (_isInitialized)
{
return;
}
_isInitialized = true;
if (environment != Environment.Trade && environment != Environment.Practice)
throw new NotSupportedException("Oanda Environment not supported: " + environment);
_api = new OandaRestApiV20(_symbolMapper, orderProvider, securityProvider, aggregator, environment, accessToken, accountId, agent);
// forward events received from API
_api.OrderStatusChanged += (sender, orderEvent) => OnOrderEvent(orderEvent);
_api.AccountChanged += (sender, accountEvent) => OnAccountChanged(accountEvent);
_api.Message += (sender, messageEvent) => OnMessage(messageEvent);
}
}
}

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -367,7 +367,7 @@ namespace QuantConnect.Brokerages.Oanda
{
if (!CanSubscribe(dataConfig.Symbol))
{
return Enumerable.Empty<BaseData>().GetEnumerator();
return null;
}
var enumerator = Aggregator.Add(dataConfig, newDataAvailableHandler);
@@ -404,7 +404,7 @@ namespace QuantConnect.Brokerages.Oanda
return false;
// ignore universe symbols
return !symbol.Value.Contains("-UNIVERSE-");
return !symbol.Value.Contains("-UNIVERSE-") && symbol.ID.Market == Market.Oanda;
}
private bool Refresh()

View File

@@ -14,17 +14,19 @@
*
*/
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NodaTime;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Packets;
using QuantConnect.Util;
using RestSharp;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NodaTime;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Packets;
using RestSharp;
namespace QuantConnect.Brokerages.Tradier
{
@@ -47,6 +49,25 @@ namespace QuantConnect.Brokerages.Tradier
/// <param name="job">Job we're subscribing for</param>
public void SetJob(LiveNodePacket job)
{
var useSandbox = bool.Parse(job.BrokerageData["tradier-use-sandbox"]);
var accountId = job.BrokerageData["tradier-account-id"];
var accessToken = job.BrokerageData["tradier-access-token"];
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"));
Initialize(
wssUrl: WebSocketUrl,
accountId: accountId,
accessToken: accessToken,
useSandbox: useSandbox,
algorithm: null,
orderProvider: null,
securityProvider: null,
aggregator: aggregator);
if (!IsConnected)
{
Connect();
}
}
/// <summary>
@@ -66,7 +87,7 @@ namespace QuantConnect.Brokerages.Tradier
if (!CanSubscribe(dataConfig.Symbol))
{
return Enumerable.Empty<BaseData>().GetEnumerator();
return null;
}
var enumerator = _aggregator.Add(dataConfig, newDataAvailableHandler);
@@ -164,6 +185,9 @@ namespace QuantConnect.Brokerages.Tradier
WebSocket.Send(json);
}
/// <summary>
/// Handles websocket received messages
/// </summary>
protected override void OnMessage(object sender, WebSocketMessage webSocketMessage)
{
var e = (WebSocketClientWrapper.TextMessage)webSocketMessage.Data;
@@ -219,7 +243,7 @@ namespace QuantConnect.Brokerages.Tradier
switch (tsd.Type)
{
case "trade":
return new Tick(time, symbol, "", tsd.TradeExchange, (int) tsd.TradeSize, tsd.TradePrice);
return new Tick(time, symbol, "", tsd.TradeExchange, (int)tsd.TradeSize, tsd.TradePrice);
case "quote":
return new Tick(time, symbol, "", "", tsd.BidSize, tsd.BidPrice, tsd.AskSize, tsd.AskPrice);
@@ -242,6 +266,6 @@ namespace QuantConnect.Brokerages.Tradier
return _streamSession;
}
#endregion
#endregion IDataQueueHandler implementation
}
}

View File

@@ -14,14 +14,6 @@
*
*/
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using QuantConnect.Data;
using QuantConnect.Interfaces;
@@ -33,6 +25,14 @@ using QuantConnect.Securities;
using QuantConnect.Securities.Equity;
using QuantConnect.Util;
using RestSharp;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
namespace QuantConnect.Brokerages.Tradier
{
@@ -47,8 +47,8 @@ namespace QuantConnect.Brokerages.Tradier
[BrokerageFactory(typeof(TradierBrokerageFactory))]
public partial class TradierBrokerage : BaseWebsocketsBrokerage, IDataQueueHandler, IDataQueueUniverseProvider, IHistoryProvider
{
private readonly bool _useSandbox;
private readonly string _accountId;
private bool _useSandbox;
private string _accountId;
// we're reusing the equity exchange here to grab typical exchange hours
private static readonly EquityExchange Exchange =
@@ -61,36 +61,51 @@ namespace QuantConnect.Brokerages.Tradier
private readonly object _lockAccessCredentials = new object();
// polling timer for checking for fill events
private readonly Timer _orderFillTimer;
private Timer _orderFillTimer;
//Tradier Spec:
private readonly Dictionary<TradierApiRequestType, RateGate> _rateLimitNextRequest;
private Dictionary<TradierApiRequestType, RateGate> _rateLimitNextRequest;
private readonly IAlgorithm _algorithm;
private readonly IOrderProvider _orderProvider;
private readonly ISecurityProvider _securityProvider;
private readonly IDataAggregator _aggregator;
private IAlgorithm _algorithm;
private IOrderProvider _orderProvider;
private ISecurityProvider _securityProvider;
private IDataAggregator _aggregator;
private readonly object _fillLock = new object();
private readonly DateTime _initializationDateTime = DateTime.Now;
private readonly ConcurrentDictionary<long, TradierCachedOpenOrder> _cachedOpenOrdersByTradierOrderID;
private ConcurrentDictionary<long, TradierCachedOpenOrder> _cachedOpenOrdersByTradierOrderID;
// this is used to block reentrance when doing look ups for orders with IDs we don't have cached
private readonly HashSet<long> _reentranceGuardByTradierOrderID = new HashSet<long>();
private readonly FixedSizeHashQueue<long> _filledTradierOrderIDs = new FixedSizeHashQueue<long>(10000);
// this is used to handle the zero crossing case, when the first order is filled we'll submit the next order
private readonly ConcurrentDictionary<long, ContingentOrderQueue> _contingentOrdersByQCOrderID = new ConcurrentDictionary<long, ContingentOrderQueue>();
private readonly ConcurrentDictionary<long, Order> _zeroCrossingOrdersByTradierClosingOrderId = new ConcurrentDictionary<long, Order>();
// this is used to block reentrance when handling contingent orders
private readonly HashSet<long> _contingentReentranceGuardByQCOrderID = new HashSet<long>();
private readonly HashSet<long> _unknownTradierOrderIDs = new HashSet<long>();
private readonly FixedSizeHashQueue<long> _verifiedUnknownTradierOrderIDs = new FixedSizeHashQueue<long>(1000);
private readonly FixedSizeHashQueue<int> _cancelledQcOrderIDs = new FixedSizeHashQueue<int>(10000);
private string _restApiUrl = "https://api.tradier.com/v1/";
private string _restApiSandboxUrl = "https://sandbox.tradier.com/v1/";
/// <summary>
/// Returns the brokerage account's base currency
/// </summary>
public override string AccountBaseCurrency => Currencies.USD;
/// <summary>
/// Create a new Tradier Object:
/// </summary>
public TradierBrokerage() : base("Tradier Brokerage")
{
}
/// <summary>
/// Create a new Tradier Object:
/// </summary>
@@ -102,46 +117,18 @@ namespace QuantConnect.Brokerages.Tradier
bool useSandbox,
string accountId,
string accessToken)
: base(WebSocketUrl, new WebSocketClientWrapper(),
new RestClient(useSandbox ? "https://sandbox.tradier.com/v1/" : "https://api.tradier.com/v1/"),
null, null, "Tradier Brokerage")
: base("Tradier Brokerage")
{
_algorithm = algorithm;
_orderProvider = orderProvider;
_securityProvider = securityProvider;
_aggregator = aggregator;
_useSandbox = useSandbox;
_accountId = accountId;
RestClient.AddDefaultHeader("Accept", "application/json");
RestClient.AddDefaultHeader("Authorization", $"Bearer {accessToken}");
var subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager();
subscriptionManager.SubscribeImpl += (symbols, _) => Subscribe(symbols);
subscriptionManager.UnsubscribeImpl += (symbols, _) => Unsubscribe(symbols);
SubscriptionManager = subscriptionManager;
_cachedOpenOrdersByTradierOrderID = new ConcurrentDictionary<long, TradierCachedOpenOrder>();
// we can poll orders once a second in sandbox and twice a second in production
var interval = _useSandbox ? 1000 : 500;
_rateLimitNextRequest = new Dictionary<TradierApiRequestType, RateGate>
{
{ TradierApiRequestType.Data, new RateGate(1, TimeSpan.FromMilliseconds(interval))},
{ TradierApiRequestType.Standard, new RateGate(1, TimeSpan.FromMilliseconds(interval))},
{ TradierApiRequestType.Orders, new RateGate(1, TimeSpan.FromMilliseconds(1000))},
};
_orderFillTimer = new Timer(state => CheckForFills(), null, interval, interval);
WebSocket.Error += (sender, error) =>
{
if (!WebSocket.IsOpen)
{
// on error we clear our state, on Open we will re susbscribe
_subscribedTickers.Clear();
_streamSession = null;
}
};
Initialize(
wssUrl: WebSocketUrl,
accountId: accountId,
accessToken: accessToken,
useSandbox: useSandbox,
algorithm: algorithm,
orderProvider: orderProvider,
securityProvider: securityProvider,
aggregator: aggregator
);
}
#region Tradier client implementation
@@ -391,7 +378,7 @@ namespace QuantConnect.Brokerages.Tradier
/// Place Order through API.
/// accounts/{account-id}/orders
/// </summary>
public TradierOrderResponse PlaceOrder(
private TradierOrderResponse PlaceOrder(
TradierOrderClass classification,
TradierOrderDirection direction,
string symbol,
@@ -604,7 +591,7 @@ namespace QuantConnect.Brokerages.Tradier
return obj;
}
#endregion
#endregion Tradier client implementation
#region IBrokerage implementation
@@ -844,7 +831,7 @@ namespace QuantConnect.Brokerages.Tradier
// success
OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, OrderFee.Zero)
{ Status = OrderStatus.UpdateSubmitted });
{ Status = OrderStatus.UpdateSubmitted });
// if we have contingents, update them as well
if (contingent != null)
@@ -899,7 +886,7 @@ namespace QuantConnect.Brokerages.Tradier
TradierCachedOpenOrder tradierOrder;
_cachedOpenOrdersByTradierOrderID.TryRemove(id, out tradierOrder);
OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, OrderFee.Zero, "Tradier Order Event")
{ Status = OrderStatus.Canceled });
{ Status = OrderStatus.Canceled });
}
}
@@ -1005,7 +992,7 @@ namespace QuantConnect.Brokerages.Tradier
{
// invalidate the order, bad request
OnOrderEvent(new OrderEvent(order.QCOrder, DateTime.UtcNow, OrderFee.Zero)
{ Status = OrderStatus.Invalid });
{ Status = OrderStatus.Invalid });
string message = _previousResponseRaw;
if (response != null && response.Errors != null && !response.Errors.Errors.IsNullOrEmpty())
@@ -1338,7 +1325,7 @@ namespace QuantConnect.Brokerages.Tradier
}
}
#endregion
#endregion IBrokerage implementation
#region Conversion routines
@@ -1373,12 +1360,14 @@ namespace QuantConnect.Brokerages.Tradier
case TradierOrderDirection.SellToOpen:
case TradierOrderDirection.SellToClose:
return true;
case TradierOrderDirection.Buy:
case TradierOrderDirection.BuyToCover:
case TradierOrderDirection.BuyToClose:
case TradierOrderDirection.BuyToOpen:
case TradierOrderDirection.None:
return false;
default:
throw new ArgumentOutOfRangeException("direction", direction, null);
}
@@ -1396,12 +1385,15 @@ namespace QuantConnect.Brokerages.Tradier
case TradierOrderType.Limit:
qcOrder = new LimitOrder { LimitPrice = order.Price };
break;
case TradierOrderType.Market:
qcOrder = new MarketOrder();
break;
case TradierOrderType.StopMarket:
qcOrder = new StopMarketOrder { StopPrice = GetOrder(order.Id).StopPrice };
break;
case TradierOrderType.StopLimit:
qcOrder = new StopLimitOrder { LimitPrice = order.Price, StopPrice = GetOrder(order.Id).StopPrice };
break;
@@ -1773,19 +1765,71 @@ namespace QuantConnect.Brokerages.Tradier
return 0;
}
#endregion
#endregion Conversion routines
/// <summary>
/// Initailze the instance of this class
/// </summary>
private void Initialize(string wssUrl,
string accountId, string accessToken, bool useSandbox, IAlgorithm algorithm,
IOrderProvider orderProvider, ISecurityProvider securityProvider, IDataAggregator aggregator)
{
if (IsInitialized)
{
return;
}
var restClient = new RestClient(useSandbox ? _restApiSandboxUrl : _restApiUrl);
base.Initialize(wssUrl, new WebSocketClientWrapper(), restClient, null, null);
_algorithm = algorithm;
_orderProvider = orderProvider;
_securityProvider = securityProvider;
_aggregator = aggregator;
_useSandbox = useSandbox;
_accountId = accountId;
RestClient.AddDefaultHeader("Accept", "application/json");
RestClient.AddDefaultHeader("Authorization", $"Bearer {accessToken}");
var subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager();
subscriptionManager.SubscribeImpl += (symbols, _) => Subscribe(symbols);
subscriptionManager.UnsubscribeImpl += (symbols, _) => Unsubscribe(symbols);
SubscriptionManager = subscriptionManager;
_cachedOpenOrdersByTradierOrderID = new ConcurrentDictionary<long, TradierCachedOpenOrder>();
// we can poll orders once a second in sandbox and twice a second in production
var interval = _useSandbox ? 1000 : 500;
_rateLimitNextRequest = new Dictionary<TradierApiRequestType, RateGate>
{
{ TradierApiRequestType.Data, new RateGate(1, TimeSpan.FromMilliseconds(interval))},
{ TradierApiRequestType.Standard, new RateGate(1, TimeSpan.FromMilliseconds(interval))},
{ TradierApiRequestType.Orders, new RateGate(1, TimeSpan.FromMilliseconds(1000))},
};
_orderFillTimer = new Timer(state => CheckForFills(), null, interval, interval);
WebSocket.Error += (sender, error) =>
{
if (!WebSocket.IsOpen)
{
// on error we clear our state, on Open we will re susbscribe
_subscribedTickers.Clear();
_streamSession = null;
}
};
}
private readonly HashSet<string> ErrorsDuringMarketHours = new HashSet<string>
{
"CheckForFillsError", "UnknownIdResolution", "ContingentOrderError", "NullResponse", "PendingOrderNotReturned"
};
class ContingentOrderQueue
private class ContingentOrderQueue
{
/// <summary>
/// The original order produced by the algorithm
/// </summary>
public readonly Order QCOrder;
/// <summary>
/// A queue of contingent orders to be placed after fills
/// </summary>
@@ -1810,7 +1854,7 @@ namespace QuantConnect.Brokerages.Tradier
}
}
class TradierCachedOpenOrder
private class TradierCachedOpenOrder
{
public bool EmittedOrderFee;
public TradierOrder Order;

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -13,13 +13,13 @@
* limitations under the License.
*/
using System.Collections.Generic;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using QuantConnect.Packets;
using QuantConnect.Securities;
using QuantConnect.Util;
using System.Collections.Generic;
namespace QuantConnect.Brokerages.Tradier
{

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -13,11 +13,12 @@
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Packets;
using QuantConnect.Util;
using System;
using System.Collections.Generic;
namespace QuantConnect.Brokerages.Zerodha
{
@@ -34,6 +35,20 @@ namespace QuantConnect.Brokerages.Zerodha
/// <param name="job">Job we're subscribing for</param>
public void SetJob(LiveNodePacket job)
{
Initialize(
job.BrokerageData["zerodha-trading-segment"],
job.BrokerageData["zerodha-product-type"],
job.BrokerageData["zerodha-api-key"],
job.BrokerageData["zerodha-access-token"],
null,
null,
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"))
);
if (!IsConnected)
{
Connect();
}
}
/// <summary>
@@ -47,7 +62,7 @@ namespace QuantConnect.Brokerages.Zerodha
var symbol = dataConfig.Symbol;
if (!CanSubscribe(symbol))
{
return Enumerable.Empty<BaseData>().GetEnumerator();
return null;
}
var enumerator = _aggregator.Add(dataConfig, newDataAvailableHandler);
@@ -66,7 +81,6 @@ namespace QuantConnect.Brokerages.Zerodha
_aggregator.Remove(dataConfig);
}
/// <summary>
/// Returns true if this data provide can handle the specified symbol
/// </summary>
@@ -82,6 +96,7 @@ namespace QuantConnect.Brokerages.Zerodha
return
(securityType == SecurityType.Equity) && (market == Market.India);
}
#endregion
#endregion IDataQueueHandler implementation
}
}

View File

@@ -14,29 +14,28 @@
*/
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NodaTime;
using QuantConnect.Brokerages.Zerodha.Messages;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Securities;
using QuantConnect.Util;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using QuantConnect.Orders.Fees;
using System.Threading;
using QuantConnect.Orders;
using QuantConnect.Brokerages.Zerodha.Messages;
using Tick = QuantConnect.Data.Market.Tick;
using System.Net.WebSockets;
using System.Text;
using Newtonsoft.Json.Linq;
using NodaTime;
using QuantConnect.Data.Market;
using QuantConnect.Configuration;
using QuantConnect.Util;
using System.Threading;
using Order = QuantConnect.Orders.Order;
using OrderType = QuantConnect.Orders.OrderType;
using Tick = QuantConnect.Data.Market.Tick;
namespace QuantConnect.Brokerages.Zerodha
{
@@ -47,6 +46,7 @@ namespace QuantConnect.Brokerages.Zerodha
public partial class ZerodhaBrokerage : Brokerage, IDataQueueHandler
{
#region Declarations
private const int ConnectionTimeout = 30000;
/// <summary>
@@ -74,37 +74,43 @@ namespace QuantConnect.Brokerages.Zerodha
/// </summary>
protected string ApiKey;
private readonly ISecurityProvider _securityProvider;
private ISecurityProvider _securityProvider;
private readonly IAlgorithm _algorithm;
private IAlgorithm _algorithm;
private readonly ConcurrentDictionary<int, decimal> _fills = new ConcurrentDictionary<int, decimal>();
private readonly DataQueueHandlerSubscriptionManager SubscriptionManager;
private DataQueueHandlerSubscriptionManager SubscriptionManager;
private ConcurrentDictionary<string, Symbol> _subscriptionsById = new ConcurrentDictionary<string, Symbol>();
private readonly IDataAggregator _aggregator;
private IDataAggregator _aggregator;
private readonly ZerodhaSymbolMapper _symbolMapper;
private ZerodhaSymbolMapper _symbolMapper;
private readonly List<string> subscribeInstrumentTokens = new List<string>();
private readonly List<string> unSubscribeInstrumentTokens = new List<string>();
private Kite _kite;
private readonly string _apiKey;
private readonly string _accessToken;
private readonly string _wssUrl = "wss://ws.kite.trade/";
private string _apiKey;
private string _accessToken;
private string _wssUrl = "wss://ws.kite.trade/";
private readonly string _tradingSegment;
private readonly BrokerageConcurrentMessageHandler<WebSocketClientWrapper.MessageData> _messageHandler;
private readonly string _zerodhaProductType;
private string _tradingSegment;
private BrokerageConcurrentMessageHandler<WebSocketClientWrapper.MessageData> _messageHandler;
private string _zerodhaProductType;
private DateTime _lastTradeTickTime;
private bool _historyDataTypeErrorFlag;
private bool _isInitialized;
#endregion
#endregion Declarations
/// <summary>
/// Constructor for brokerage
/// </summary>
public ZerodhaBrokerage() : base("Zerodha")
{
}
/// <summary>
/// Constructor for brokerage
@@ -119,37 +125,7 @@ namespace QuantConnect.Brokerages.Zerodha
public ZerodhaBrokerage(string tradingSegment, string zerodhaProductType, string apiKey, string apiSecret, IAlgorithm algorithm, ISecurityProvider securityProvider, IDataAggregator aggregator)
: base("Zerodha")
{
_tradingSegment = tradingSegment;
_zerodhaProductType = zerodhaProductType;
_algorithm = algorithm;
_aggregator = aggregator;
_kite = new Kite(apiKey, apiSecret);
_apiKey = apiKey;
_accessToken = apiSecret;
_securityProvider = securityProvider;
_messageHandler = new BrokerageConcurrentMessageHandler<WebSocketClientWrapper.MessageData>(OnMessageImpl);
WebSocket = new WebSocketClientWrapper();
_wssUrl += string.Format(CultureInfo.InvariantCulture, "?api_key={0}&access_token={1}", _apiKey, _accessToken);
WebSocket.Initialize(_wssUrl);
WebSocket.Message += OnMessage;
WebSocket.Open += (sender, args) =>
{
Log.Trace($"ZerodhaBrokerage(): WebSocket.Open. Subscribing");
Subscribe(GetSubscribed());
};
WebSocket.Error += OnError;
_symbolMapper = new ZerodhaSymbolMapper(_kite);
var subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager();
subscriptionManager.SubscribeImpl += (s, t) =>
{
Subscribe(s);
return true;
};
subscriptionManager.UnsubscribeImpl += (s, t) => Unsubscribe(s);
SubscriptionManager = subscriptionManager;
Log.Trace("Start Zerodha Brokerage");
Initialize(tradingSegment, zerodhaProductType, apiKey, apiSecret, algorithm, securityProvider, aggregator);
}
/// <summary>
@@ -188,7 +164,6 @@ namespace QuantConnect.Brokerages.Zerodha
WebSocket.Send(requestFullMode);
}
/// <summary>
/// Get list of subscribed symbol
/// </summary>
@@ -214,7 +189,7 @@ namespace QuantConnect.Brokerages.Zerodha
continue;
}
foreach (var instrumentToken in instrumentTokenList)
{
{
var tokenStringInvariant = instrumentToken.ToStringInvariant();
if (!unSubscribeInstrumentTokens.Contains(tokenStringInvariant))
{
@@ -230,10 +205,8 @@ namespace QuantConnect.Brokerages.Zerodha
return true;
}
return false;
}
/// <summary>
/// Gets Quote using Zerodha API
/// </summary>
@@ -346,7 +319,6 @@ namespace QuantConnect.Brokerages.Zerodha
throw;
}
}
#region IBrokerage
@@ -395,7 +367,6 @@ namespace QuantConnect.Brokerages.Zerodha
}
}
/// <summary>
/// Places a new order and assigns a new broker ID to the order
/// </summary>
@@ -407,9 +378,8 @@ namespace QuantConnect.Brokerages.Zerodha
_messageHandler.WithLockedStream(() =>
{
uint orderQuantity = Convert.ToUInt32(Math.Abs(order.Quantity));
JObject orderResponse = new JObject();;
JObject orderResponse = new JObject(); ;
decimal? triggerPrice = GetOrderTriggerPrice(order);
decimal? orderPrice = GetOrderPrice(order);
@@ -433,7 +403,7 @@ namespace QuantConnect.Brokerages.Zerodha
}
else if (string.IsNullOrEmpty(zerodhaProductType))
{
throw new ArgumentException("Please set ProductType in config or provide a value in DefaultOrderProperties");
throw new ArgumentException("Please set ProductType in config or provide a value in DefaultOrderProperties");
}
try
{
@@ -442,14 +412,12 @@ namespace QuantConnect.Brokerages.Zerodha
}
catch (Exception ex)
{
var errorMessage = $"Order failed, Order Id: {order.Id} timestamp: {order.Time} quantity: {order.Quantity} content: {ex.Message}";
OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, orderFee, "Zerodha Order Event") { Status = OrderStatus.Invalid });
OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Warning, -1, errorMessage));
return;
}
if ((string)orderResponse["status"] == "success")
{
if (string.IsNullOrEmpty((string)orderResponse["data"]["order_id"]))
@@ -538,23 +506,25 @@ namespace QuantConnect.Brokerages.Zerodha
private static string ConvertOrderType(OrderType orderType)
{
switch (orderType)
{
case OrderType.Limit:
return "LIMIT";
case OrderType.Market:
return "MARKET";
case OrderType.StopMarket:
return "SL-M";
case OrderType.StopLimit:
return "SL";
default:
throw new NotSupportedException($"ZerodhaBrokerage.ConvertOrderType: Unsupported order type: {orderType}");
}
}
/// <summary>
/// Updates the order with the same id
/// </summary>
@@ -566,7 +536,6 @@ namespace QuantConnect.Brokerages.Zerodha
_messageHandler.WithLockedStream(() =>
{
if (!order.Status.IsOpen())
{
OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Warning, "error", "Order is already being processed"));
@@ -574,7 +543,7 @@ namespace QuantConnect.Brokerages.Zerodha
}
var orderProperties = order.Properties as IndiaOrderProperties;
var zerodhaProductType = _zerodhaProductType;
var zerodhaProductType = _zerodhaProductType;
if (orderProperties == null || orderProperties.Exchange == null)
{
var errorMessage = $"Order failed, Order Id: {order.Id} timestamp: {order.Time} quantity: {order.Quantity} content: Please specify a valid order properties with an exchange value";
@@ -587,16 +556,16 @@ namespace QuantConnect.Brokerages.Zerodha
}
else if (string.IsNullOrEmpty(zerodhaProductType))
{
throw new ArgumentException("Please set ProductType in config or provide a value in DefaultOrderProperties");
throw new ArgumentException("Please set ProductType in config or provide a value in DefaultOrderProperties");
}
uint orderQuantity = Convert.ToUInt32(Math.Abs(order.Quantity));
JObject orderResponse = new JObject();;
JObject orderResponse = new JObject(); ;
decimal? triggerPrice = GetOrderTriggerPrice(order);
decimal? orderPrice = GetOrderPrice(order);
var kiteOrderType = ConvertOrderType(order.Type);
var orderFee = OrderFee.Zero;
try
{
orderResponse = _kite.ModifyOrder(order.BrokerId[0].ToStringInvariant(),
@@ -615,13 +584,11 @@ namespace QuantConnect.Brokerages.Zerodha
}
catch (Exception ex)
{
OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, orderFee, "Zerodha Update Order Event") { Status = OrderStatus.Invalid });
OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Warning, -1, $"Order failed, Order Id: {order.Id} timestamp: {order.Time} quantity: {order.Quantity} content: {ex.Message}"));
return;
}
if ((string)orderResponse["status"] == "success")
{
if (string.IsNullOrEmpty((string)orderResponse["data"]["order_id"]))
@@ -668,12 +635,11 @@ namespace QuantConnect.Brokerages.Zerodha
/// <param name="order">The order to cancel</param>
/// <returns>True if the request was submitted for cancellation, false otherwise</returns>
public override bool CancelOrder(Order order)
{
{
var submitted = false;
_messageHandler.WithLockedStream(() =>
{
JObject orderResponse = new JObject();
if (order.Status.IsOpen())
{
@@ -705,10 +671,8 @@ namespace QuantConnect.Brokerages.Zerodha
return;
});
return submitted;
}
/// <summary>
/// Gets all orders not yet closed
/// </summary>
@@ -756,7 +720,6 @@ namespace QuantConnect.Brokerages.Zerodha
order.Status = ConvertOrderStatus(item);
order.Price = item.Price;
list.Add(order);
}
foreach (var item in list)
{
@@ -799,8 +762,6 @@ namespace QuantConnect.Brokerages.Zerodha
return OrderStatus.None;
}
/// <summary>
/// Gets all open postions and account holdings
/// </summary>
@@ -813,15 +774,13 @@ namespace QuantConnect.Brokerages.Zerodha
var productTypeNRML = KiteProductType.NRML.ToString().ToUpperInvariant();
var productTypeCNC = KiteProductType.CNC.ToString().ToUpperInvariant();
// get MIS and NRML Positions
if (string.IsNullOrEmpty(_zerodhaProductType) || zerodhaProductTypeUpper == productTypeMIS || zerodhaProductTypeUpper == productTypeNRML)
if (string.IsNullOrEmpty(_zerodhaProductType) || zerodhaProductTypeUpper == productTypeMIS || zerodhaProductTypeUpper == productTypeNRML)
{
var PositionsResponse = _kite.GetPositions();
if (PositionsResponse.Day.Count != 0)
{
foreach (var item in PositionsResponse.Day)
{
Holding holding = new Holding
{
AveragePrice = item.AveragePrice,
@@ -831,14 +790,13 @@ namespace QuantConnect.Brokerages.Zerodha
UnrealizedPnL = item.Unrealised,
CurrencySymbol = Currencies.GetCurrencySymbol(AccountBaseCurrency),
MarketValue = item.ClosePrice * item.Quantity
};
holdingsList.Add(holding);
}
}
}
// get CNC Positions
if (string.IsNullOrEmpty(_zerodhaProductType) || zerodhaProductTypeUpper == productTypeCNC )
if (string.IsNullOrEmpty(_zerodhaProductType) || zerodhaProductTypeUpper == productTypeCNC)
{
var HoldingResponse = _kite.GetHoldings();
if (HoldingResponse != null)
@@ -897,7 +855,7 @@ namespace QuantConnect.Brokerages.Zerodha
_historyDataTypeErrorFlag = true;
yield break;
}
if (request.Symbol.SecurityType != SecurityType.Equity && request.Symbol.SecurityType != SecurityType.Future && request.Symbol.SecurityType != SecurityType.Option)
{
OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Warning, "InvalidSecurityType",
@@ -930,7 +888,7 @@ namespace QuantConnect.Brokerages.Zerodha
}
var history = Enumerable.Empty<BaseData>();
var symbol = request.Symbol;
var start = request.StartTimeLocal;
var end = request.EndTimeLocal;
@@ -961,6 +919,46 @@ namespace QuantConnect.Brokerages.Zerodha
}
}
private void Initialize(string tradingSegment, string zerodhaProductType, string apiKey, string apiSecret,
IAlgorithm algorithm, ISecurityProvider securityProvider, IDataAggregator aggregator)
{
if (_isInitialized)
{
return;
}
_isInitialized = true;
_tradingSegment = tradingSegment;
_zerodhaProductType = zerodhaProductType;
_algorithm = algorithm;
_aggregator = aggregator;
_kite = new Kite(apiKey, apiSecret);
_apiKey = apiKey;
_accessToken = apiSecret;
_securityProvider = securityProvider;
_messageHandler = new BrokerageConcurrentMessageHandler<WebSocketClientWrapper.MessageData>(OnMessageImpl);
WebSocket = new WebSocketClientWrapper();
_wssUrl += string.Format(CultureInfo.InvariantCulture, "?api_key={0}&access_token={1}", _apiKey, _accessToken);
WebSocket.Initialize(_wssUrl);
WebSocket.Message += OnMessage;
WebSocket.Open += (sender, args) =>
{
Log.Trace($"ZerodhaBrokerage(): WebSocket.Open. Subscribing");
Subscribe(GetSubscribed());
};
WebSocket.Error += OnError;
_symbolMapper = new ZerodhaSymbolMapper(_kite);
var subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager();
subscriptionManager.SubscribeImpl += (s, t) =>
{
Subscribe(s);
return true;
};
subscriptionManager.UnsubscribeImpl += (s, t) => Unsubscribe(s);
SubscriptionManager = subscriptionManager;
Log.Trace("ZerodhaBrokerage(): Zerodha Brokerage initialized");
}
private IEnumerable<BaseData> GetHistoryForPeriod(Symbol symbol, DateTime start, DateTime end, DateTimeZone exchangeTimeZone, Resolution resolution, string zerodhaResolution)
{
Log.Debug("ZerodhaBrokerage.GetHistoryForPeriod();");
@@ -981,7 +979,7 @@ namespace QuantConnect.Brokerages.Zerodha
foreach (var candle in candles)
{
yield return new TradeBar(candle.TimeStamp.ConvertFromUtc(exchangeTimeZone),symbol,candle.Open,candle.High,candle.Low,candle.Close,candle.Volume,resolution.ToTimeSpan());
yield return new TradeBar(candle.TimeStamp.ConvertFromUtc(exchangeTimeZone), symbol, candle.Open, candle.High, candle.Low, candle.Close, candle.Volume, resolution.ToTimeSpan());
}
}
@@ -1045,7 +1043,7 @@ namespace QuantConnect.Brokerages.Zerodha
var bestBidQuote = tick.Bids[0];
var bestAskQuote = tick.Offers[0];
var instrumentTokenValue = tick.InstrumentToken;
var instrumentTokenValue = tick.InstrumentToken;
var time = tick.Timestamp ?? DateTime.UtcNow.ConvertFromUtc(TimeZones.Kolkata);
@@ -1252,7 +1250,6 @@ namespace QuantConnect.Brokerages.Zerodha
tick.OIDayLow = ReadInt(b, ref offset);
tick.Timestamp = Time.UnixTimeStampToDateTime(ReadInt(b, ref offset));
tick.Bids = new DepthItem[5];
for (int i = 0; i < 5; i++)
{
@@ -1272,8 +1269,7 @@ namespace QuantConnect.Brokerages.Zerodha
}
return tick;
}
#endregion
#endregion IBrokerage
}
}

View File

@@ -16,6 +16,7 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using QuantConnect.Optimizer.Parameters;
using QuantConnect.Statistics;
namespace QuantConnect.Api
@@ -29,86 +30,92 @@ namespace QuantConnect.Api
/// Name of the backtest
/// </summary>
[JsonProperty(PropertyName = "name")]
public string Name;
public string Name { get; set; }
/// <summary>
/// Note on the backtest attached by the user
/// </summary>
[JsonProperty(PropertyName = "note")]
public string Note;
public string Note { get; set; }
/// <summary>
/// Assigned backtest Id
/// </summary>
[JsonProperty(PropertyName = "backtestId")]
public string BacktestId;
public string BacktestId { get; set; }
/// <summary>
/// Boolean true when the backtest is completed.
/// </summary>
[JsonProperty(PropertyName = "completed")]
public bool Completed;
public bool Completed { get; set; }
/// <summary>
/// Progress of the backtest in percent 0-1.
/// </summary>
[JsonProperty(PropertyName = "progress")]
public decimal Progress;
public decimal Progress { get; set; }
/// <summary>
/// Backtest error message
/// </summary>
[JsonProperty(PropertyName = "error")]
public string Error;
public string Error { get; set; }
/// <summary>
/// Backtest error stacktrace
/// </summary>
[JsonProperty(PropertyName = "stacktrace")]
public string StackTrace;
public string StackTrace { get; set; }
/// <summary>
/// Backtest creation date and time
/// </summary>
[JsonProperty(PropertyName = "created")]
public DateTime Created;
public DateTime Created { get; set; }
/// <summary>
/// Rolling window detailed statistics.
/// </summary>
[JsonProperty(PropertyName = "rollingWindow", NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<string, AlgorithmPerformance> RollingWindow;
public Dictionary<string, AlgorithmPerformance> RollingWindow { get; set; }
/// <summary>
/// Rolling window detailed statistics.
/// </summary>
[JsonProperty(PropertyName = "totalPerformance", NullValueHandling = NullValueHandling.Ignore)]
public AlgorithmPerformance TotalPerformance;
public AlgorithmPerformance TotalPerformance { get; set; }
/// <summary>
/// Contains population averages scores over the life of the algorithm
/// </summary>
[JsonProperty(PropertyName = "alphaRuntimeStatistics", NullValueHandling = NullValueHandling.Ignore)]
public AlphaRuntimeStatistics AlphaRuntimeStatistics;
public AlphaRuntimeStatistics AlphaRuntimeStatistics { get; set; }
/// <summary>
/// Charts updates for the live algorithm since the last result packet
/// </summary>
[JsonProperty(PropertyName = "charts", NullValueHandling = NullValueHandling.Ignore)]
public IDictionary<string, Chart> Charts;
public IDictionary<string, Chart> Charts { get; set; }
/// <summary>
/// Statistics information sent during the algorithm operations.
/// </summary>
/// <remarks>Intended for update mode -- send updates to the existing statistics in the result GUI. If statistic key does not exist in GUI, create it</remarks>
[JsonProperty(PropertyName = "statistics", NullValueHandling = NullValueHandling.Ignore)]
public IDictionary<string, string> Statistics;
public IDictionary<string, string> Statistics { get; set; }
/// <summary>
/// Runtime banner/updating statistics in the title banner of the live algorithm GUI.
/// </summary>
[JsonProperty(PropertyName = "runtimeStatistics", NullValueHandling = NullValueHandling.Ignore)]
public IDictionary<string, string> RuntimeStatistics;
public IDictionary<string, string> RuntimeStatistics { get; set; }
/// <summary>
/// Optimization parameters
/// </summary>
[JsonProperty(PropertyName = "parameterSet")]
public ParameterSet ParameterSet { get; set; }
}
/// <summary>
@@ -121,7 +128,7 @@ namespace QuantConnect.Api
/// Backtest Object
/// </summary>
[JsonProperty(PropertyName = "backtest")]
public Backtest Backtest;
public Backtest Backtest { get; set; }
}
/// <summary>
@@ -133,6 +140,6 @@ namespace QuantConnect.Api
/// Collection of summarized backtest objects
/// </summary>
[JsonProperty(PropertyName = "backtests")]
public List<Backtest> Backtests;
public List<Backtest> Backtests { get; set; }
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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 QuantConnect.Optimizer;
using QuantConnect.Optimizer.Objectives;
namespace QuantConnect.Api
{
/// <summary>
/// BaseOptimization item from the QuantConnect.com API.
/// </summary>
public class BaseOptimization : RestResponse
{
/// <summary>
/// Optimization ID
/// </summary>
[JsonProperty(PropertyName = "optimizationId")]
public string OptimizationId { get; set; }
/// <summary>
/// Project ID of the project the optimization belongs to
/// </summary>
[JsonProperty(PropertyName = "projectId")]
public int ProjectId { get; set; }
/// <summary>
/// Name of the optimization
/// </summary>
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
/// <summary>
/// Status of the optimization
/// </summary>
[JsonProperty(PropertyName = "status")]
public OptimizationStatus Status { get; set; }
/// <summary>
/// Optimization node type
/// </summary>
/// <remarks><see cref="OptimizationNodes"/></remarks>
[JsonProperty(PropertyName = "nodeType")]
public string NodeType { get; set; }
/// <summary>
/// Optimization statistical target
/// </summary>
[JsonProperty(PropertyName = "criterion")]
public Target Criterion { get; set; }
}
}

View File

@@ -28,19 +28,19 @@ namespace QuantConnect.Api
/// Compile Id for a sucessful build
/// </summary>
[JsonProperty(PropertyName = "compileId")]
public string CompileId;
public string CompileId { get; set; }
/// <summary>
/// True on successful compile
/// </summary>
[JsonProperty(PropertyName = "state")]
[JsonConverter(typeof(StringEnumConverter))]
public CompileState State;
public CompileState State { get; set; }
/// <summary>
/// Logs of the compilation request
/// </summary>
[JsonProperty(PropertyName = "logs")]
public List<string> Logs;
public List<string> Logs { get; set; }
}
}

56
Common/Api/Estimate.cs Normal file
View File

@@ -0,0 +1,56 @@
/*
* 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 Newtonsoft.Json;
namespace QuantConnect.Api
{
/// <summary>
/// Estimate response packet from the QuantConnect.com API.
/// </summary>
public class Estimate
{
/// <summary>
/// Estimate id
/// </summary>
[JsonProperty(PropertyName = "estimateId")]
public string EstimateId { get; set; }
/// <summary>
/// Estimate time in seconds
/// </summary>
[JsonProperty(PropertyName = "time")]
public int Time { get; set; }
/// <summary>
/// Estimate balance in QCC
/// </summary>
[JsonProperty(PropertyName = "balance")]
public int Balance { get; set; }
}
/// <summary>
/// Wrapper class for Optimizations/* endpoints JSON response
/// Currently used by Optimizations/Estimate
/// </summary>
public class EstimateResponseWrapper : RestResponse
{
/// <summary>
/// Estimate object
/// </summary>
[JsonProperty(PropertyName = "estimate")]
public Estimate Estimate { get; set; }
}
}

View File

@@ -27,37 +27,37 @@ namespace QuantConnect.Api
/// Project id for the live instance
/// </summary>
[JsonProperty(PropertyName = "projectId")]
public int ProjectId;
public int ProjectId { get; set; }
/// <summary>
/// Unique live algorithm deployment identifier (similar to a backtest id).
/// </summary>
[JsonProperty(PropertyName = "deployId")]
public string DeployId;
public string DeployId { get; set; }
/// <summary>
/// Algorithm status: running, stopped or runtime error.
/// </summary>
[JsonProperty(PropertyName = "status")]
public AlgorithmStatus Status;
public AlgorithmStatus Status { get; set; }
/// <summary>
/// Datetime the algorithm was launched in UTC.
/// </summary>
[JsonProperty(PropertyName = "launched")]
public DateTime Launched;
public DateTime Launched { get; set; }
/// <summary>
/// Datetime the algorithm was stopped in UTC, null if its still running.
/// </summary>
[JsonProperty(PropertyName = "stopped")]
public DateTime? Stopped;
public DateTime? Stopped { get; set; }
/// <summary>
/// Brokerage
/// </summary>
[JsonProperty(PropertyName = "brokerage")]
public string Brokerage;
public string Brokerage { get; set; }
/// <summary>
/// Chart we're subscribed to
@@ -66,13 +66,13 @@ namespace QuantConnect.Api
/// Data limitations mean we can only stream one chart at a time to the consumer. See which chart you're watching here.
/// </remarks>
[JsonProperty(PropertyName = "subscription")]
public string Subscription;
public string Subscription { get; set; }
/// <summary>
/// Live algorithm error message from a crash or algorithm runtime error.
/// </summary>
[JsonProperty(PropertyName = "error")]
public string Error;
public string Error { get; set; }
}
/// <summary>
@@ -84,6 +84,6 @@ namespace QuantConnect.Api
/// Algorithm list matching the requested status.
/// </summary>
[JsonProperty(PropertyName = "live")]
public List<LiveAlgorithm> Algorithms;
public List<LiveAlgorithm> Algorithms { get; set; }
}
}

View File

@@ -73,18 +73,6 @@ namespace QuantConnect.Api
{
var jObject = JObject.Load(reader);
var liveResults = CreateLiveResultsFromJObject(jObject);
return liveResults;
}
/// <summary>
/// Custom parsing of live results data
/// </summary>
/// <param name="jObject">Json representing LiveResults</param>
/// <returns></returns>
public static LiveAlgorithmResults CreateLiveResultsFromJObject(JObject jObject)
{
var liveAlgoResults = new LiveAlgorithmResults
{
Success = jObject["success"].Value<bool>()

View File

@@ -103,19 +103,19 @@ namespace QuantConnect.Api
/// Collection of backtest nodes
/// </summary>
[JsonProperty(PropertyName = "backtest")]
public List<Node> BacktestNodes;
public List<Node> BacktestNodes { get; set; }
/// <summary>
/// Collection of research nodes
/// </summary>
[JsonProperty(PropertyName = "research")]
public List<Node> ResearchNodes;
public List<Node> ResearchNodes { get; set; }
/// <summary>
/// Collection of live nodes
/// </summary>
[JsonProperty(PropertyName = "live")]
public List<Node> LiveNodes;
public List<Node> LiveNodes { get; set; }
}
/// <summary>
@@ -143,17 +143,17 @@ namespace QuantConnect.Api
/// <summary>
/// The number of CPU cores in the node
/// </summary>
public int Cores;
public int Cores { get; set; }
/// <summary>
/// Size of RAM in GB of the Node
/// </summary>
public int Memory;
public int Memory { get; set; }
/// <summary>
/// Target environment for the node
/// </summary>
public NodeType Target;
public NodeType Target { get; set; }
/// <summary>
/// Constructs a SKU object out of the provided node configuration
@@ -234,4 +234,24 @@ namespace QuantConnect.Api
public int Yearly { get; set; }
}
/// <summary>
/// Supported optimization nodes
/// </summary>
public static class OptimizationNodes
{
/// <summary>
/// 2 CPUs 8 GB ram
/// </summary>
public static string O2_8 => "O2-8";
/// <summary>
/// 4 CPUs 12 GB ram
/// </summary>
public static string O4_12 => "O4-12";
/// <summary>
/// 8 CPUs 16 GB ram
/// </summary>
public static string O8_16 => "O8-16";
}
}

View File

@@ -0,0 +1,95 @@
/*
* 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 System.Collections.Generic;
using Newtonsoft.Json;
using QuantConnect.Optimizer.Objectives;
using QuantConnect.Optimizer.Parameters;
namespace QuantConnect.Api
{
/// <summary>
/// Optimization response packet from the QuantConnect.com API.
/// </summary>
public class Optimization : BaseOptimization
{
/// <summary>
/// Runtime banner/updating statistics for the optimization
/// </summary>
[JsonProperty(PropertyName = "runtimeStatistics", NullValueHandling = NullValueHandling.Ignore)]
public IDictionary<string, string> RuntimeStatistics { get; set; }
/// <summary>
/// Optimization constraints
/// </summary>
[JsonProperty(PropertyName = "constraints", NullValueHandling = NullValueHandling.Ignore)]
public IReadOnlyList<Constraint> Constraints { get; set; }
/// <summary>
/// Optimization parameters
/// </summary>
[JsonProperty(PropertyName = "parameters", NullValueHandling = NullValueHandling.Ignore)]
public HashSet<OptimizationParameter> Parameters { get; set; }
/// <summary>
/// Number of parallel nodes for optimization
/// </summary>
[JsonProperty(PropertyName = "parallelNodes")]
public int ParallelNodes { get; set; }
/// <summary>
/// Optimization constraints
/// </summary>
[JsonProperty(PropertyName = "backtests", NullValueHandling = NullValueHandling.Ignore)]
public IDictionary<string, OptimizationBacktest> Backtests { get; set; }
/// <summary>
/// Optimization strategy
/// </summary>
[JsonProperty(PropertyName = "strategy")]
public string Strategy { get; set; }
/// <summary>
/// Optimization requested date and time
/// </summary>
[JsonProperty(PropertyName = "requested")]
public DateTime Requested { get; set; }
}
/// <summary>
/// Wrapper class for Optimizations/Read endpoint JSON response
/// </summary>
public class OptimizationResponseWrapper : RestResponse
{
/// <summary>
/// Optimization object
/// </summary>
[JsonProperty(PropertyName = "optimization")]
public Optimization Optimization { get; set; }
}
/// <summary>
/// Collection container for a list of summarized optimizations for a project
/// </summary>
public class OptimizationList : RestResponse
{
/// <summary>
/// Collection of summarized optimization objects
/// </summary>
[JsonProperty(PropertyName = "optimizations")]
public List<BaseOptimization> Optimizations { get; set; }
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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 Newtonsoft.Json;
using QuantConnect.Optimizer.Parameters;
namespace QuantConnect.Api
{
/// <summary>
/// OptimizationBacktest object from the QuantConnect.com API.
/// </summary>
[JsonConverter(typeof(OptimizationBacktestJsonConverter))]
public class OptimizationBacktest
{
/// <summary>
/// Progress of the backtest as a percentage from 0-1 based on the days lapsed from start-finish.
/// </summary>
public decimal Progress { get; set; }
/// <summary>
/// The backtest name
/// </summary>
public string Name { get; }
/// <summary>
/// The backtest host name
/// </summary>
public string HostName { get; set; }
/// <summary>
/// The backtest id
/// </summary>
public string BacktestId { get; }
/// <summary>
/// Represent a combination as key value of parameters, i.e. order doesn't matter
/// </summary>
public ParameterSet ParameterSet { get; }
/// <summary>
/// The backtest statistics results
/// </summary>
public IDictionary<string, string> Statistics { get; set; }
/// <summary>
/// The backtest equity chart series
/// </summary>
public Series Equity { get; set; }
/// <summary>
/// The exit code of this backtest
/// </summary>
public int ExitCode { get; set; }
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="parameterSet">The parameter set</param>
/// <param name="backtestId">The backtest id if any</param>
/// <param name="name">The backtest name</param>
public OptimizationBacktest(ParameterSet parameterSet, string backtestId, string name)
{
ParameterSet = parameterSet;
BacktestId = backtestId;
Name = name;
}
}
}

View File

@@ -0,0 +1,202 @@
/*
* 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 System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using QuantConnect.Optimizer.Parameters;
using QuantConnect.Statistics;
using QuantConnect.Util;
namespace QuantConnect.Api
{
/// <summary>
/// Json converter for <see cref="OptimizationBacktest"/> which creates a light weight easy to consume serialized version
/// </summary>
public class OptimizationBacktestJsonConverter : JsonConverter
{
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(OptimizationBacktest);
}
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var optimizationBacktest = value as OptimizationBacktest;
if (ReferenceEquals(optimizationBacktest, null)) return;
writer.WriteStartObject();
if (!string.IsNullOrEmpty(optimizationBacktest.Name))
{
writer.WritePropertyName("name");
writer.WriteValue(optimizationBacktest.Name);
}
if (!string.IsNullOrEmpty(optimizationBacktest.BacktestId))
{
writer.WritePropertyName("id");
writer.WriteValue(optimizationBacktest.BacktestId);
writer.WritePropertyName("progress");
writer.WriteValue(optimizationBacktest.Progress);
writer.WritePropertyName("exitCode");
writer.WriteValue(optimizationBacktest.ExitCode);
}
if (!optimizationBacktest.Statistics.IsNullOrEmpty())
{
writer.WritePropertyName("statistics");
writer.WriteStartArray();
foreach (var keyValuePair in optimizationBacktest.Statistics.OrderBy(pair => pair.Key))
{
var statistic = keyValuePair.Value.Replace("%", string.Empty).Replace("$", string.Empty);
if (string.IsNullOrEmpty(statistic))
{
continue;
}
decimal result;
if (decimal.TryParse(statistic, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
{
writer.WriteValue(result);
}
}
writer.WriteEndArray();
}
if (optimizationBacktest.ParameterSet != null)
{
writer.WritePropertyName("parameterSet");
serializer.Serialize(writer, optimizationBacktest.ParameterSet.Value);
}
if (optimizationBacktest.Equity != null)
{
writer.WritePropertyName("equity");
writer.WriteStartArray();
foreach (var chartPoint in optimizationBacktest.Equity.Values)
{
writer.WriteStartArray();
writer.WriteValue(chartPoint.x);
writer.WriteValue(chartPoint.y);
writer.WriteEndArray();
}
writer.WriteEndArray();
}
writer.WriteEndObject();
}
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>
/// The object value.
/// </returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
var name = jObject["name"].Value<string>();
var hostName = jObject["hostName"]?.Value<string>();
var backtestId = jObject["id"].Value<string>();
var progress = jObject["progress"].Value<decimal>();
var exitCode = jObject["exitCode"].Value<int>();
var jStatistics = jObject["statistics"];
var statistics = new Dictionary<string, string>
{
{ PerformanceMetrics.Alpha, jStatistics[0].Value<string>() },
{ PerformanceMetrics.AnnualStandardDeviation, jStatistics[1].Value<string>() },
{ PerformanceMetrics.AnnualVariance, jStatistics[2].Value<string>() },
{ PerformanceMetrics.AverageLoss, jStatistics[3].Value<string>() },
{ PerformanceMetrics.AverageWin, jStatistics[4].Value<string>() },
{ PerformanceMetrics.Beta, jStatistics[5].Value<string>() },
{ PerformanceMetrics.CompoundingAnnualReturn, jStatistics[6].Value<string>() },
{ PerformanceMetrics.Drawdown, jStatistics[7].Value<string>() },
{ PerformanceMetrics.EstimatedStrategyCapacity, jStatistics[8].Value<string>() },
{ PerformanceMetrics.Expectancy, jStatistics[9].Value<string>() },
{ PerformanceMetrics.InformationRatio, jStatistics[10].Value<string>() },
{ PerformanceMetrics.LossRate, jStatistics[11].Value<string>() },
{ PerformanceMetrics.NetProfit, jStatistics[12].Value<string>() },
{ PerformanceMetrics.ProbabilisticSharpeRatio, jStatistics[13].Value<string>() },
{ PerformanceMetrics.ProfitLossRatio, jStatistics[14].Value<string>() },
{ PerformanceMetrics.SharpeRatio, jStatistics[15].Value<string>() },
{ PerformanceMetrics.TotalFees, jStatistics[16].Value<string>() },
{ PerformanceMetrics.TotalTrades, jStatistics[17].Value<string>() },
{ PerformanceMetrics.TrackingError, jStatistics[18].Value<string>() },
{ PerformanceMetrics.TreynorRatio, jStatistics[19].Value<string>() },
{ PerformanceMetrics.WinRate, jStatistics[20].Value<string>() },
};
var parameterSet = serializer.Deserialize<ParameterSet>(jObject["parameterSet"].CreateReader());
var equity = new Series { Values = GetSeriesValues(jObject["equity"]) };
var optimizationBacktest = new OptimizationBacktest(parameterSet, backtestId, name)
{
HostName = hostName,
Progress = progress,
ExitCode = exitCode,
Statistics = statistics,
Equity = equity
};
return optimizationBacktest;
}
/// <summary>
/// Get x and y value pairs that represent series data
/// </summary>
/// <param name="values">json array of x, y value pairs</param>
/// <returns>List of ChartPoints</returns>
private static List<ChartPoint> GetSeriesValues(JToken values)
{
var chartPoints = new List<ChartPoint>();
foreach (var point in values.Children())
{
var x = point[0];
var y = point[1];
chartPoints.Add(new ChartPoint((long)x, (decimal)y));
}
return chartPoints;
}
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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 System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using QuantConnect.Optimizer.Parameters;
namespace QuantConnect.Api
{
/// <summary>
/// Json converter for <see cref="ParameterSet"/> which creates a light weight easy to consume serialized version
/// </summary>
public class ParameterSetJsonConverter : JsonConverter
{
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ParameterSet);
}
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
var parameterSet = value as ParameterSet;
if (ReferenceEquals(parameterSet, null)) return;
writer.WriteStartObject();
if (parameterSet.Value != null)
{
writer.WritePropertyName("parameterSet");
serializer.Serialize(writer, parameterSet.Value);
}
writer.WriteEndObject();
}
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>
/// The object value.
/// </returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
var value = jObject["parameterSet"] ?? jObject;
var parameterSet = new ParameterSet(-1, value.ToObject<Dictionary<string, string>>());
return parameterSet;
}
}
}

View File

@@ -27,31 +27,31 @@ namespace QuantConnect.Api
/// Project id
/// </summary>
[JsonProperty(PropertyName = "projectId")]
public int ProjectId;
public int ProjectId { get; set; }
/// <summary>
/// Name of the project
/// </summary>
[JsonProperty(PropertyName = "name")]
public string Name;
public string Name { get; set; }
/// <summary>
/// Date the project was created
/// </summary>
[JsonProperty(PropertyName = "created")]
public DateTime Created;
public DateTime Created { get; set; }
/// <summary>
/// Modified date for the project
/// </summary>
[JsonProperty(PropertyName = "modified")]
public DateTime Modified;
public DateTime Modified { get; set; }
/// <summary>
/// Programming language of the project
/// </summary>
[JsonProperty(PropertyName = "language")]
public Language Language;
public Language Language { get; set; }
}
/// <summary>
@@ -63,6 +63,6 @@ namespace QuantConnect.Api
/// List of projects for the authenticated user
/// </summary>
[JsonProperty(PropertyName = "projects")]
public List<Project> Projects;
public List<Project> Projects { get; set; }
}
}

View File

@@ -28,13 +28,13 @@ namespace QuantConnect.Api
/// Name of a project file
/// </summary>
[JsonProperty(PropertyName = "name")]
public string Name;
public string Name { get; set; }
/// <summary>
/// Contents of the project file
/// </summary>
[JsonProperty(PropertyName = "content")]
public string Code;
public string Code { get; set; }
/// <summary>
/// DateTime project file was modified
@@ -52,6 +52,6 @@ namespace QuantConnect.Api
/// List of project file information
/// </summary>
[JsonProperty(PropertyName = "files")]
public List<ProjectFile> Files;
public List<ProjectFile> Files { get; set; }
}
}

View File

@@ -35,12 +35,12 @@ namespace QuantConnect.Api
/// Indicate if the API request was successful.
/// </summary>
[JsonProperty(PropertyName = "success")]
public bool Success;
public bool Success { get; set; }
/// <summary>
/// List of errors with the API call.
/// </summary>
[JsonProperty(PropertyName = "errors")]
public List<string> Errors;
public List<string> Errors { get; set; }
}
}

View File

@@ -59,11 +59,6 @@ namespace QuantConnect.Brokerages
/// <returns>The leverage for the specified security</returns>
public override decimal GetLeverage(Security security)
{
if (AccountType == AccountType.Cash)
{
return 1m;
}
switch (security.Type)
{
case SecurityType.Forex:

View File

@@ -49,7 +49,7 @@ namespace QuantConnect.Brokerages
{SecurityType.Future, Market.CME},
{SecurityType.FutureOption, Market.CME},
{SecurityType.Forex, Market.Oanda},
{SecurityType.Cfd, Market.FXCM},
{SecurityType.Cfd, Market.Oanda},
{SecurityType.Crypto, Market.GDAX},
{SecurityType.Index, Market.USA},
{SecurityType.IndexOption, Market.USA}

View File

@@ -116,7 +116,7 @@ namespace QuantConnect.Data
var fileData = currentFileData;
writeTasks.Enqueue(Task.Run(() =>
{
WriteFile(file, fileData, data.Time);
WriteFile(file, fileData);
}));
}
@@ -139,7 +139,7 @@ namespace QuantConnect.Data
{
writeTasks.Enqueue(Task.Run(() =>
{
WriteFile(outputFile, currentFileData, lastTime);
WriteFile(outputFile, currentFileData);
}));
}
@@ -258,16 +258,19 @@ namespace QuantConnect.Data
/// </summary>
/// <param name="filePath">The full path to the new file</param>
/// <param name="data">The data to write as a list of dates and strings</param>
/// <param name="date">The date the data represents</param>
/// <remarks>The reason we have the data as IEnumerable(DateTime, string) is to support
/// a generic write that works for all resolutions. In order to merge in hour/daily case I need the
/// date of the data to correctly merge the two. In order to support writing ticks I need to allow
/// two data points to have the same time. Thus I cannot use a single list of just strings nor
/// a sorted dictionary of DateTimes and strings. </remarks>
private void WriteFile(string filePath, IEnumerable<(DateTime, string)> data, DateTime date)
private void WriteFile(string filePath, List<(DateTime, string)> data)
{
if (data == null || data.Count == 0)
{
return;
}
// Generate this csv entry name
var entryName = LeanData.GenerateZipEntryName(_symbol, date, _resolution, _tickType);
var entryName = LeanData.GenerateZipEntryName(_symbol, data[0].Item1, _resolution, _tickType);
// Check disk once for this file ahead of time, reuse where possible
var fileExists = File.Exists(filePath);

View File

@@ -20,7 +20,6 @@ using System.ComponentModel;
using QuantConnect.Securities;
using System.Collections.Generic;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Market;
using static QuantConnect.StringExtensions;
namespace QuantConnect.Data
@@ -30,6 +29,7 @@ namespace QuantConnect.Data
/// </summary>
public class SubscriptionDataConfig : IEquatable<SubscriptionDataConfig>
{
private readonly bool _mappedConfig;
private readonly SecurityIdentifier _sid;
/// <summary>
@@ -205,7 +205,8 @@ namespace QuantConnect.Data
bool isFilteredSubscription = true,
DataNormalizationMode dataNormalizationMode = DataNormalizationMode.Adjusted,
DataMappingMode dataMappingMode = DataMappingMode.OpenInterest,
uint contractDepthOffset = 0)
uint contractDepthOffset = 0,
bool mappedConfig = false)
{
if (objectType == null) throw new ArgumentNullException(nameof(objectType));
if (symbol == null) throw new ArgumentNullException(nameof(symbol));
@@ -222,6 +223,7 @@ namespace QuantConnect.Data
IsInternalFeed = isInternalFeed;
IsCustomData = isCustom;
DataTimeZone = dataTimeZone;
_mappedConfig = mappedConfig;
DataMappingMode = dataMappingMode;
ExchangeTimeZone = exchangeTimeZone;
ContractDepthOffset = contractDepthOffset;
@@ -276,6 +278,8 @@ namespace QuantConnect.Data
/// <param name="dataMappingMode">The contract mapping mode to use for the security</param>
/// <param name="contractDepthOffset">The continuous contract desired offset from the current front month.
/// For example, 0 (default) will use the front month, 1 will use the back month contract</param>
/// <param name="mappedConfig">True if this is created as a mapped config. This is useful for continuous contract at live trading
/// where we subscribe to the mapped symbol but want to preserve uniqueness</param>
public SubscriptionDataConfig(SubscriptionDataConfig config,
Type objectType = null,
Symbol symbol = null,
@@ -290,7 +294,8 @@ namespace QuantConnect.Data
bool? isFilteredSubscription = null,
DataNormalizationMode? dataNormalizationMode = null,
DataMappingMode? dataMappingMode = null,
uint? contractDepthOffset = null)
uint? contractDepthOffset = null,
bool? mappedConfig = null)
: this(
objectType ?? config.Type,
symbol ?? config.Symbol,
@@ -305,7 +310,8 @@ namespace QuantConnect.Data
isFilteredSubscription ?? config.IsFilteredSubscription,
dataNormalizationMode ?? config.DataNormalizationMode,
dataMappingMode ?? config.DataMappingMode,
contractDepthOffset ?? config.ContractDepthOffset
contractDepthOffset ?? config.ContractDepthOffset,
mappedConfig ?? false
)
{
PriceScaleFactor = config.PriceScaleFactor;
@@ -335,7 +341,8 @@ namespace QuantConnect.Data
&& DataMappingMode == other.DataMappingMode
&& ExchangeTimeZone.Equals(other.ExchangeTimeZone)
&& ContractDepthOffset == other.ContractDepthOffset
&& IsFilteredSubscription == other.IsFilteredSubscription;
&& IsFilteredSubscription == other.IsFilteredSubscription
&& _mappedConfig == other._mappedConfig;
}
/// <summary>
@@ -376,6 +383,7 @@ namespace QuantConnect.Data
hashCode = (hashCode*397) ^ ExchangeTimeZone.Id.GetHashCode();// timezone hash is expensive, use id instead
hashCode = (hashCode*397) ^ ContractDepthOffset.GetHashCode();
hashCode = (hashCode*397) ^ IsFilteredSubscription.GetHashCode();
hashCode = (hashCode*397) ^ _mappedConfig.GetHashCode();
return hashCode;
}
}

View File

@@ -14,8 +14,8 @@
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Collections.Generic;
namespace QuantConnect.Data.UniverseSelection
{

View File

@@ -0,0 +1,148 @@
/*
* 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 System.Linq;
using QuantConnect.Util;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using System.Collections.Generic;
using QuantConnect.Configuration;
using QuantConnect.Data.Auxiliary;
namespace QuantConnect.Data.UniverseSelection
{
/// <summary>
/// Continuous contract universe selection that based on the requested mapping mode will select each symbol
/// </summary>
public class ContinuousContractUniverse : Universe, ITimeTriggeredUniverse
{
private readonly IMapFileProvider _mapFileProvider;
private readonly Security _security;
private readonly bool _liveMode;
private Symbol _currentSymbol;
private string _mappedSymbol;
/// <summary>
/// Gets the settings used for subscriptions added for this universe
/// </summary>
public override UniverseSettings UniverseSettings { get; }
/// <summary>
/// Creates a new instance
/// </summary>
public ContinuousContractUniverse(Security security, UniverseSettings universeSettings, bool liveMode, SubscriptionDataConfig universeConfig)
: base(universeConfig)
{
_security = security;
_liveMode = liveMode;
UniverseSettings = universeSettings;
var mapFileProviderTypeName = Config.Get("map-file-provider", "LocalDiskMapFileProvider");
_mapFileProvider = Composer.Instance.GetExportedValueByTypeName<IMapFileProvider>(mapFileProviderTypeName);
}
/// <summary>
/// Performs universe selection based on the symbol mapping
/// </summary>
/// <param name="utcTime">The current utc time</param>
/// <param name="data">Empty data</param>
/// <returns>The symbols to use</returns>
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
{
yield return _security.Symbol.Canonical;
var mapFile = _mapFileProvider.ResolveMapFile(new SubscriptionDataConfig(Configuration,
dataMappingMode: UniverseSettings.DataMappingMode,
symbol: _security.Symbol.Canonical));
var mappedSymbol = mapFile.GetMappedSymbol(utcTime.ConvertFromUtc(_security.Exchange.TimeZone));
if (!string.IsNullOrEmpty(mappedSymbol) && mappedSymbol != _mappedSymbol)
{
if (_currentSymbol != null)
{
// let's emit the old and new for the mapping date
yield return _currentSymbol;
}
_mappedSymbol = mappedSymbol;
_currentSymbol = _security.Symbol.Canonical
.UpdateMappedSymbol(mappedSymbol, Configuration.ContractDepthOffset)
.Underlying;
}
if (_currentSymbol != null)
{
((IContinuousSecurity)_security).Mapped = _currentSymbol;
yield return _currentSymbol;
}
}
/// <summary>
/// Gets the subscription requests to be added for the specified security
/// </summary>
/// <param name="security">The security to get subscriptions for</param>
/// <param name="currentTimeUtc">The current time in utc. This is the frontier time of the algorithm</param>
/// <param name="maximumEndTimeUtc">The max end time</param>
/// <param name="subscriptionService">Instance which implements <see cref="ISubscriptionDataConfigService"/> interface</param>
/// <returns>All subscriptions required by this security</returns>
public override IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security,
DateTime currentTimeUtc,
DateTime maximumEndTimeUtc,
ISubscriptionDataConfigService subscriptionService)
{
var isInternal = !security.Symbol.IsCanonical();
var result = subscriptionService.Add(security.Symbol,
UniverseSettings.Resolution,
UniverseSettings.FillForward,
UniverseSettings.ExtendedMarketHours,
dataNormalizationMode: UniverseSettings.DataNormalizationMode,
subscriptionDataTypes: UniverseSettings.SubscriptionDataTypes,
dataMappingMode: UniverseSettings.DataMappingMode,
contractDepthOffset: (uint)Math.Abs(UniverseSettings.ContractDepthOffset),
isInternalFeed: isInternal);
return result.Select(config => new SubscriptionRequest(isUniverseSubscription: false,
universe: this,
security: security,
configuration: new SubscriptionDataConfig(config, isInternalFeed: config.IsInternalFeed || config.TickType == TickType.OpenInterest),
startTimeUtc: currentTimeUtc,
endTimeUtc: maximumEndTimeUtc));
}
/// <summary>
/// Each tradeable day of the future we trigger a new selection.
/// Allows use to select the current contract
/// </summary>
public IEnumerable<DateTime> GetTriggerTimes(DateTime startTimeUtc, DateTime endTimeUtc, MarketHoursDatabase marketHoursDatabase)
{
var startTimeLocal = startTimeUtc.ConvertFromUtc(_security.Exchange.TimeZone);
var endTimeLocal = endTimeUtc.ConvertFromUtc(_security.Exchange.TimeZone);
return Time.EachTradeableDay(_security, startTimeLocal, endTimeLocal)
// in live trading we delay selection so that we make sure auxiliary data is ready
.Select(time => _liveMode ? time.Add(Time.LiveAuxiliaryDataOffset) : time);
}
/// <summary>
/// Creates a continuous universe symbol
/// </summary>
/// <param name="symbol">The associated symbol</param>
/// <returns>A symbol for a continuous universe of the specified symbol</returns>
public static Symbol CreateSymbol(Symbol symbol)
{
var ticker = $"qc-universe-continuous-{symbol.ID.Market.ToLowerInvariant()}-{symbol.SecurityType}-{symbol.ID.Symbol}";
return UniverseExtensions.CreateSymbol(symbol.SecurityType, symbol.ID.Market, ticker);
}
}
}

View File

@@ -26,16 +26,12 @@ namespace QuantConnect.Data.UniverseSelection
/// </summary>
public class FineFundamentalUniverse : Universe
{
private readonly UniverseSettings _universeSettings;
private readonly Func<IEnumerable<FineFundamental>, IEnumerable<Symbol>> _selector;
/// <summary>
/// Gets the settings used for subscriptons added for this universe
/// Gets the settings used for subscriptions added for this universe
/// </summary>
public override UniverseSettings UniverseSettings
{
get { return _universeSettings; }
}
public override UniverseSettings UniverseSettings { get; }
/// <summary>
/// Initializes a new instance of the <see cref="FineFundamentalUniverse"/> class
@@ -45,7 +41,7 @@ namespace QuantConnect.Data.UniverseSelection
public FineFundamentalUniverse(UniverseSettings universeSettings, Func<IEnumerable<FineFundamental>, IEnumerable<Symbol>> selector)
: base(CreateConfiguration(FineFundamental.CreateUniverseSymbol(QuantConnect.Market.USA)))
{
_universeSettings = universeSettings;
UniverseSettings = universeSettings;
_selector = selector;
}
@@ -58,7 +54,7 @@ namespace QuantConnect.Data.UniverseSelection
public FineFundamentalUniverse(Symbol symbol, UniverseSettings universeSettings, Func<IEnumerable<FineFundamental>, IEnumerable<Symbol>> selector)
: base(CreateConfiguration(symbol))
{
_universeSettings = universeSettings;
UniverseSettings = universeSettings;
_selector = selector;
}

View File

@@ -122,9 +122,10 @@ namespace QuantConnect.Data.UniverseSelection
/// </summary>
/// <param name="utcTime">The current utc date time</param>
/// <param name="security">The security to be added</param>
/// <param name="isInternal">True if internal member</param>
/// <returns>True if the security was successfully added,
/// false if the security was already in the universe</returns>
internal override bool AddMember(DateTime utcTime, Security security)
internal override bool AddMember(DateTime utcTime, Security security, bool isInternal)
{
// never add members to disposed universes
if (DisposeRequested)
@@ -145,7 +146,7 @@ namespace QuantConnect.Data.UniverseSelection
Securities.TryRemove(security.Symbol, out member);
}
var added = Securities.TryAdd(security.Symbol, new Member(utcTime, security));
var added = Securities.TryAdd(security.Symbol, new Member(utcTime, security, isInternal));
if (added && _liveMode)
{

View File

@@ -13,10 +13,10 @@
* limitations under the License.
*/
using System.Collections.Generic;
using System;
using System.Linq;
using QuantConnect.Securities;
using QuantConnect.Util;
using System.Collections.Generic;
namespace QuantConnect.Data.UniverseSelection
{
@@ -28,15 +28,19 @@ namespace QuantConnect.Data.UniverseSelection
/// <summary>
/// Gets an instance that represents no changes have been made
/// </summary>
public static readonly SecurityChanges None = new SecurityChanges(new List<Security>(), new List<Security>());
public static readonly SecurityChanges None = new (Enumerable.Empty<Security>(), Enumerable.Empty<Security>(),
Enumerable.Empty<Security>(), Enumerable.Empty<Security>());
private readonly HashSet<Security> _addedSecurities;
private readonly HashSet<Security> _removedSecurities;
private readonly IReadOnlySet<Security> _addedSecurities;
private readonly IReadOnlySet<Security> _removedSecurities;
private readonly IReadOnlySet<Security> _internalAddedSecurities;
private readonly IReadOnlySet<Security> _internalRemovedSecurities;
/// <summary>
/// Gets the total count of added and removed securities
/// </summary>
public int Count => _addedSecurities.Count + _removedSecurities.Count;
public int Count => _addedSecurities.Count + _removedSecurities.Count
+ _internalAddedSecurities.Count + _internalRemovedSecurities.Count;
/// <summary>
/// True will filter out custom securities from the
@@ -46,20 +50,23 @@ namespace QuantConnect.Data.UniverseSelection
/// the filtering if desired</remarks>
public bool FilterCustomSecurities { get; set; }
/// <summary>
/// True will filter out internal securities from the
/// <see cref="AddedSecurities"/> and <see cref="RemovedSecurities"/> properties
/// </summary>
/// <remarks>This allows us to filter but also to disable
/// the filtering if desired</remarks>
public bool FilterInternalSecurities { get; set; }
/// <summary>
/// Gets the symbols that were added by universe selection
/// </summary>
/// <remarks>Will use <see cref="FilterCustomSecurities"/> value
/// to determine if custom securities should be filtered</remarks>
public IReadOnlyList<Security> AddedSecurities
{
get
{
return _addedSecurities.OrderBy(x => x.Symbol.Value)
.Where(security => !FilterCustomSecurities || security.Type != SecurityType.Base)
.ToList();
}
}
/// <remarks>Will use <see cref="FilterInternalSecurities"/> value
/// to determine if internal securities should be filtered</remarks>
public IReadOnlyList<Security> AddedSecurities => GetFilteredList(_addedSecurities,
!FilterInternalSecurities ? _internalAddedSecurities : null);
/// <summary>
/// Gets the symbols that were removed by universe selection. This list may
@@ -68,25 +75,25 @@ namespace QuantConnect.Data.UniverseSelection
/// </summary>
/// <remarks>Will use <see cref="FilterCustomSecurities"/> value
/// to determine if custom securities should be filtered</remarks>
public IReadOnlyList<Security> RemovedSecurities
{
get
{
return _removedSecurities.OrderBy(x => x.Symbol.Value)
.Where(security => !FilterCustomSecurities || security.Type != SecurityType.Base)
.ToList();
}
}
/// <remarks>Will use <see cref="FilterInternalSecurities"/> value
/// to determine if internal securities should be filtered</remarks>
public IReadOnlyList<Security> RemovedSecurities => GetFilteredList(_removedSecurities,
!FilterInternalSecurities ? _internalRemovedSecurities : null);
/// <summary>
/// Initializes a new instance of the <see cref="SecurityChanges"/> class
/// </summary>
/// <param name="addedSecurities">Added symbols list</param>
/// <param name="removedSecurities">Removed symbols list</param>
public SecurityChanges(IEnumerable<Security> addedSecurities, IEnumerable<Security> removedSecurities)
/// <param name="additions">Added symbols list</param>
/// <param name="removals">Removed symbols list</param>
/// <param name="internalAdditions">Internal added symbols list</param>
/// <param name="internalRemovals">Internal removed symbols list</param>
private SecurityChanges(IEnumerable<Security> additions, IEnumerable<Security> removals,
IEnumerable<Security> internalAdditions, IEnumerable<Security> internalRemovals)
{
_addedSecurities = addedSecurities.ToHashSet();
_removedSecurities = removedSecurities.ToHashSet();
_addedSecurities = additions.ToHashSet();
_removedSecurities = removals.ToHashSet();
_internalAddedSecurities = internalAdditions.ToHashSet();
_internalRemovedSecurities = internalRemovals.ToHashSet();
}
/// <summary>
@@ -98,28 +105,8 @@ namespace QuantConnect.Data.UniverseSelection
{
_addedSecurities = changes._addedSecurities;
_removedSecurities = changes._removedSecurities;
}
/// <summary>
/// Returns a new instance of <see cref="SecurityChanges"/> with the specified securities marked as added
/// </summary>
/// <param name="securities">The added securities</param>
/// <returns>A new security changes instance with the specified securities marked as added</returns>
public static SecurityChanges Added(params Security[] securities)
{
if (securities == null || securities.Length == 0) return None;
return new SecurityChanges(securities.ToList(), new List<Security>());
}
/// <summary>
/// Returns a new instance of <see cref="SecurityChanges"/> with the specified securities marked as removed
/// </summary>
/// <param name="securities">The removed securities</param>
/// <returns>A new security changes instance with the specified securities marked as removed</returns>
public static SecurityChanges Removed(params Security[] securities)
{
if (securities == null || securities.Length == 0) return None;
return new SecurityChanges(new List<Security>(), securities.ToList());
_internalAddedSecurities = changes._internalAddedSecurities;
_internalRemovedSecurities = changes._internalRemovedSecurities;
}
/// <summary>
@@ -127,17 +114,39 @@ namespace QuantConnect.Data.UniverseSelection
/// </summary>
/// <param name="left">The left side of the operand</param>
/// <param name="right">The right side of the operand</param>
/// <returns>Adds the additions together and removes any removals found in the additions, that is, additions take precendence</returns>
/// <returns>Adds the additions together and removes any removals found in the additions, that is, additions take precedence</returns>
public static SecurityChanges operator +(SecurityChanges left, SecurityChanges right)
{
// common case is adding something to nothing, shortcut these to prevent linqness
if (left == None) return right;
if (right == None) return left;
if (left == None || left.Count == 0) return right;
if (right == None || right.Count == 0) return left;
// perf: no need to use Union here, SecurityChanges.Constructor will use hashset
var additions = left.AddedSecurities.Concat(right.AddedSecurities).ToHashSet();
var removals = left.RemovedSecurities.Concat(right.RemovedSecurities).Where(x => !additions.Contains(x));
return new SecurityChanges(additions, removals);
var additions = Merge(left._addedSecurities, right._addedSecurities);
var internalAdditions = Merge(left._internalAddedSecurities, right._internalAddedSecurities);
var removals = Merge(left._removedSecurities, right._removedSecurities,
security => !additions.Contains(security) && !internalAdditions.Contains(security));
var internalRemovals = Merge(left._internalRemovedSecurities, right._internalRemovedSecurities,
security => !additions.Contains(security) && !internalAdditions.Contains(security));
return new SecurityChanges(additions, removals, internalAdditions, internalRemovals);
}
/// <summary>
/// Initializes a new instance of the <see cref="SecurityChanges"/> class all none internal
/// </summary>
/// <param name="additions">Added symbols list</param>
/// <param name="removals">Removed symbols list</param>
/// <param name="internalAdditions">Internal added symbols list</param>
/// <param name="internalRemovals">Internal removed symbols list</param>
/// <remarks>Useful for testing</remarks>
public static SecurityChanges Create(IReadOnlyCollection<Security> additions, IReadOnlyCollection<Security> removals,
IReadOnlyCollection<Security> internalAdditions, IReadOnlyCollection<Security> internalRemovals)
{
// return None if there's no changes, otherwise return what we've modified
return additions?.Count + removals?.Count + internalAdditions?.Count + internalRemovals?.Count > 0
? new SecurityChanges(additions, removals, internalAdditions, internalRemovals)
: None;
}
#region Overrides of Object
@@ -171,5 +180,106 @@ namespace QuantConnect.Data.UniverseSelection
}
#endregion
/// <summary>
/// Helper method to filter added and removed securities based on current settings
/// </summary>
private IReadOnlyList<Security> GetFilteredList(IEnumerable<Security> source, IEnumerable<Security> secondSource = null)
{
if (secondSource != null)
{
source = source.Union(secondSource);
}
return source.Where(kvp => !FilterCustomSecurities || kvp.Type != SecurityType.Base)
.Select(kvp => kvp)
.OrderBy(security => security.Symbol.Value)
.ToList();
}
/// <summary>
/// Helper method that will merge two security sets, taken into account an optional filter
/// </summary>
/// <returns>Will return merged set</returns>
private static HashSet<Security> Merge(IReadOnlyCollection<Security> left, IReadOnlyCollection<Security> right, Func<Security, bool> filter = null)
{
// if right is emtpy we just use left
IEnumerable<Security> result = left;
if (right.Count != 0)
{
if (left.Count == 0)
{
// left is emtpy so let's just use right
result = right;
}
else
{
// merge, both are not empty
result = result.Concat(right);
}
}
if (filter != null)
{
result = result.Where(filter.Invoke);
}
return new HashSet<Security>(result);
}
}
}
/// <summary>
/// Helper method to create security changes
/// </summary>
public class SecurityChangesConstructor
{
private readonly List<Security> _internalAdditions = new();
private readonly List<Security> _internalRemovals = new();
private readonly List<Security> _additions = new();
private readonly List<Security> _removals = new();
/// <summary>
/// Inserts a security addition change
/// </summary>
public void Add(Security security, bool isInternal)
{
if (isInternal)
{
_internalAdditions.Add(security);
}
else
{
_additions.Add(security);
}
}
/// <summary>
/// Inserts a security removal change
/// </summary>
public void Remove(Security security, bool isInternal)
{
if (isInternal)
{
_internalRemovals.Add(security);
}
else
{
_removals.Add(security);
}
}
/// <summary>
/// Get the current security changes clearing state
/// </summary>
public SecurityChanges Flush()
{
var result = SecurityChanges.Create(_additions, _removals, _internalAdditions, _internalRemovals);
_internalAdditions.Clear();
_removals.Clear();
_internalRemovals.Clear();
_additions.Clear();
return result;
}
}
}

View File

@@ -277,9 +277,10 @@ namespace QuantConnect.Data.UniverseSelection
/// </summary>
/// <param name="utcTime">The current utc date time</param>
/// <param name="security">The security to be added</param>
/// <param name="isInternal">True if internal member</param>
/// <returns>True if the security was successfully added,
/// false if the security was already in the universe</returns>
internal virtual bool AddMember(DateTime utcTime, Security security)
internal virtual bool AddMember(DateTime utcTime, Security security, bool isInternal)
{
// never add members to disposed universes
if (DisposeRequested)
@@ -292,7 +293,7 @@ namespace QuantConnect.Data.UniverseSelection
return false;
}
return Securities.TryAdd(security.Symbol, new Member(utcTime, security));
return Securities.TryAdd(security.Symbol, new Member(utcTime, security, isInternal));
}
/// <summary>
@@ -386,15 +387,22 @@ namespace QuantConnect.Data.UniverseSelection
/// </summary>
public readonly Security Security;
/// <summary>
/// True if the security was added as internal by this universe
/// </summary>
public readonly bool IsInternal;
/// <summary>
/// Initialize a new member for the universe
/// </summary>
/// <param name="added">DateTime added</param>
/// <param name="security">Security to add</param>
public Member(DateTime added, Security security)
/// <param name="isInternal">True if internal member</param>
public Member(DateTime added, Security security, bool isInternal)
{
Added = added;
Security = security;
IsInternal = isInternal;
}
}

View File

@@ -13,6 +13,7 @@
* limitations under the License.
*/
using System;
using System.Linq;
namespace QuantConnect.Data.UniverseSelection
@@ -72,5 +73,68 @@ namespace QuantConnect.Data.UniverseSelection
return second.SelectSymbols(utcTime, clone);
});
}
/// <summary>
/// Creates a universe symbol
/// </summary>
/// <param name="securityType">The security</param>
/// <param name="market">The market</param>
/// <param name="ticker">The Universe ticker</param>
/// <returns>A symbol for user defined universe of the specified security type and market</returns>
public static Symbol CreateSymbol(SecurityType securityType, string market, string ticker)
{
SecurityIdentifier sid;
switch (securityType)
{
case SecurityType.Base:
sid = SecurityIdentifier.GenerateBase(null, ticker, market);
break;
case SecurityType.Equity:
sid = SecurityIdentifier.GenerateEquity(SecurityIdentifier.DefaultDate, ticker, market);
break;
case SecurityType.Option:
var underlying = SecurityIdentifier.GenerateEquity(SecurityIdentifier.DefaultDate, ticker, market);
sid = SecurityIdentifier.GenerateOption(SecurityIdentifier.DefaultDate, underlying, market, 0, 0, 0);
break;
case SecurityType.FutureOption:
var underlyingFuture = SecurityIdentifier.GenerateFuture(SecurityIdentifier.DefaultDate, ticker, market);
sid = SecurityIdentifier.GenerateOption(SecurityIdentifier.DefaultDate, underlyingFuture, market, 0, 0, 0);
break;
case SecurityType.IndexOption:
var underlyingIndex = SecurityIdentifier.GenerateIndex(ticker, market);
sid = SecurityIdentifier.GenerateOption(SecurityIdentifier.DefaultDate, underlyingIndex, market, 0, 0, OptionStyle.European);
break;
case SecurityType.Forex:
sid = SecurityIdentifier.GenerateForex(ticker, market);
break;
case SecurityType.Cfd:
sid = SecurityIdentifier.GenerateCfd(ticker, market);
break;
case SecurityType.Index:
sid = SecurityIdentifier.GenerateIndex(ticker, market);
break;
case SecurityType.Future:
sid = SecurityIdentifier.GenerateFuture(SecurityIdentifier.DefaultDate, ticker, market);
break;
case SecurityType.Crypto:
sid = SecurityIdentifier.GenerateCrypto(ticker, market);
break;
case SecurityType.Commodity:
default:
throw new NotImplementedException($"The specified security type is not implemented yet: {securityType}");
}
return new Symbol(sid, ticker);
}
}
}
}

View File

@@ -110,58 +110,7 @@ namespace QuantConnect.Data.UniverseSelection
public static Symbol CreateSymbol(SecurityType securityType, string market)
{
var ticker = $"qc-universe-userdefined-{market.ToLowerInvariant()}-{securityType}";
SecurityIdentifier sid;
switch (securityType)
{
case SecurityType.Base:
sid = SecurityIdentifier.GenerateBase(null, ticker, market);
break;
case SecurityType.Equity:
sid = SecurityIdentifier.GenerateEquity(SecurityIdentifier.DefaultDate, ticker, market);
break;
case SecurityType.Option:
var underlying = SecurityIdentifier.GenerateEquity(SecurityIdentifier.DefaultDate, ticker, market);
sid = SecurityIdentifier.GenerateOption(SecurityIdentifier.DefaultDate, underlying, market, 0, 0, 0);
break;
case SecurityType.FutureOption:
var underlyingFuture = SecurityIdentifier.GenerateFuture(SecurityIdentifier.DefaultDate, ticker, market);
sid = SecurityIdentifier.GenerateOption(SecurityIdentifier.DefaultDate, underlyingFuture, market, 0, 0, 0);
break;
case SecurityType.IndexOption:
var underlyingIndex = SecurityIdentifier.GenerateIndex(ticker, market);
sid = SecurityIdentifier.GenerateOption(SecurityIdentifier.DefaultDate, underlyingIndex, market, 0, 0, OptionStyle.European);
break;
case SecurityType.Forex:
sid = SecurityIdentifier.GenerateForex(ticker, market);
break;
case SecurityType.Cfd:
sid = SecurityIdentifier.GenerateCfd(ticker, market);
break;
case SecurityType.Index:
sid = SecurityIdentifier.GenerateIndex(ticker, market);
break;
case SecurityType.Future:
sid = SecurityIdentifier.GenerateFuture(SecurityIdentifier.DefaultDate, ticker, market);
break;
case SecurityType.Crypto:
sid = SecurityIdentifier.GenerateCrypto(ticker, market);
break;
case SecurityType.Commodity:
default:
throw new NotImplementedException($"The specified security type is not implemented yet: {securityType}");
}
return new Symbol(sid, ticker);
return UniverseExtensions.CreateSymbol(securityType, market, ticker);
}
/// <summary>

View File

@@ -0,0 +1,86 @@
/*
* 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 System.Linq;
using Newtonsoft.Json;
using System.Reflection;
namespace QuantConnect
{
/// <summary>
/// Custom attribute used for documentation
/// </summary>
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
[DocumentationAttribute("Reference")]
public sealed class DocumentationAttribute : Attribute
{
private static readonly DocumentationAttribute Attribute =
typeof(DocumentationAttribute).GetCustomAttributes<DocumentationAttribute>().Single();
private static readonly string BasePath =
Attribute.FileName.Substring(0, Attribute.FileName.LastIndexOf("Common", StringComparison.Ordinal));
/// <summary>
/// The documentation tag
/// </summary>
[JsonProperty(PropertyName = "tag")]
public string Tag { get; }
/// <summary>
/// The associated weight of this attribute and tag
/// </summary>
[JsonProperty(PropertyName = "weight")]
public int Weight { get; }
/// <summary>
/// The associated line of this attribute
/// </summary>
[JsonProperty(PropertyName = "line")]
public int Line { get; }
/// <summary>
/// The associated file name of this attribute
/// </summary>
[JsonProperty(PropertyName = "fileName")]
public string FileName { get; }
/// <summary>
/// The attributes type id, we override it to ignore it when serializing
/// </summary>
[JsonIgnore]
public override object TypeId => base.TypeId;
/// <summary>
/// Creates a new instance
/// </summary>
public DocumentationAttribute(string tag, int weight = 0,
[System.Runtime.CompilerServices.CallerLineNumber] int line = 0,
[System.Runtime.CompilerServices.CallerFilePath] string fileName = "")
{
Tag = tag;
Line = line;
Weight = weight;
// will be null for the attribute of DocumentationAttribute itself
if (BasePath != null)
{
FileName = fileName.Replace(BasePath, string.Empty, StringComparison.InvariantCultureIgnoreCase);
}
else
{
FileName = fileName;
}
}
}
}

View File

@@ -151,6 +151,25 @@ namespace QuantConnect
return marketHoursDatabase.GetEntry(symbol.ID.Market, symbol, symbol.ID.SecurityType);
}
/// <summary>
/// Helper method to deserialize a json array into a list also handling single json values
/// </summary>
/// <param name="jsonArray">The value to deserialize</param>
public static List<string> DeserializeList(this string jsonArray)
{
List<string> result = new();
try
{
result = JsonConvert.DeserializeObject<List<string>>(jsonArray);
}
catch(JsonReaderException)
{
result.Add(jsonArray);
}
return result;
}
/// <summary>
/// Helper method to download a provided url as a string
/// </summary>
@@ -1335,6 +1354,26 @@ namespace QuantConnect
return value;
}
/// <summary>
/// Helper method to determine if a data type implements the Stream reader method
/// </summary>
public static bool ImplementsStreamReader(this Type baseDataType)
{
// we know these type implement the streamReader interface lets avoid dynamic reflection call to figure it out
if (baseDataType == typeof(TradeBar) || baseDataType == typeof(QuoteBar) || baseDataType == typeof(Tick))
{
return true;
}
var method = baseDataType.GetMethod("Reader",
new[] { typeof(SubscriptionDataConfig), typeof(StreamReader), typeof(DateTime), typeof(bool) });
if (method != null && method.DeclaringType == baseDataType)
{
return true;
}
return false;
}
/// <summary>
/// Breaks the specified string into csv components, all commas are considered separators
/// </summary>
@@ -2921,6 +2960,21 @@ namespace QuantConnect
}
}
/// <summary>
/// Helper method to determine symbol for a live subscription
/// </summary>
/// <remarks>Useful for continuous futures where we subscribe to the underlying</remarks>
public static bool TryGetLiveSubscriptionSymbol(this Symbol symbol, out Symbol mapped)
{
mapped = null;
if (symbol.SecurityType == SecurityType.Future && symbol.IsCanonical() && symbol.HasUnderlying)
{
mapped = symbol.Underlying;
return true;
}
return false;
}
/// <summary>
/// Gets the delisting date for the provided Symbol
/// </summary>
@@ -2987,6 +3041,35 @@ namespace QuantConnect
return symbol;
}
/// <summary>
/// Helper method to unsubscribe a given configuration, handling any required mapping
/// </summary>
public static void UnsubscribeWithMapping(this IDataQueueHandler dataQueueHandler, SubscriptionDataConfig dataConfig)
{
if (dataConfig.Symbol.TryGetLiveSubscriptionSymbol(out var mappedSymbol))
{
dataConfig = new SubscriptionDataConfig(dataConfig, symbol: mappedSymbol, mappedConfig: true);
}
dataQueueHandler.Unsubscribe(dataConfig);
}
/// <summary>
/// Helper method to subscribe a given configuration, handling any required mapping
/// </summary>
public static IEnumerator<BaseData> SubscribeWithMapping(this IDataQueueHandler dataQueueHandler,
SubscriptionDataConfig dataConfig,
EventHandler newDataAvailableHandler,
out SubscriptionDataConfig subscribedConfig)
{
subscribedConfig = dataConfig;
if (dataConfig.Symbol.TryGetLiveSubscriptionSymbol(out var mappedSymbol))
{
subscribedConfig = new SubscriptionDataConfig(dataConfig, symbol: mappedSymbol, mappedConfig: true);
}
var enumerator = dataQueueHandler.Subscribe(subscribedConfig, newDataAvailableHandler);
return enumerator ?? Enumerable.Empty<BaseData>().GetEnumerator();
}
/// <summary>
/// Helper method to stream read lines from a file
/// </summary>
@@ -3003,10 +3086,16 @@ namespace QuantConnect
using (var streamReader = new StreamReader(stream))
{
while (!streamReader.EndOfStream)
string line;
do
{
yield return streamReader.ReadLine();
line = streamReader.ReadLine();
if (line != null)
{
yield return line;
}
}
while (line != null);
}
}
@@ -3138,6 +3227,41 @@ namespace QuantConnect
}
}
/// <summary>
/// Thread safe concurrent dictionary order by implementation by using <see cref="SafeEnumeration{TSource,TKey}"/>
/// </summary>
/// <remarks>See https://stackoverflow.com/questions/47630824/is-c-sharp-linq-orderby-threadsafe-when-used-with-concurrentdictionarytkey-tva</remarks>
public static IOrderedEnumerable<KeyValuePair<TSource, TKey>> OrderBySafe<TSource, TKey>(
this ConcurrentDictionary<TSource, TKey> source, Func<KeyValuePair<TSource, TKey>, TSource> keySelector
)
{
return source.SafeEnumeration().OrderBy(keySelector);
}
/// <summary>
/// Thread safe concurrent dictionary order by implementation by using <see cref="SafeEnumeration{TSource,TKey}"/>
/// </summary>
/// <remarks>See https://stackoverflow.com/questions/47630824/is-c-sharp-linq-orderby-threadsafe-when-used-with-concurrentdictionarytkey-tva</remarks>
public static IOrderedEnumerable<KeyValuePair<TSource, TKey>> OrderBySafe<TSource, TKey>(
this ConcurrentDictionary<TSource, TKey> source, Func<KeyValuePair<TSource, TKey>, TKey> keySelector
)
{
return source.SafeEnumeration().OrderBy(keySelector);
}
/// <summary>
/// Force concurrent dictionary enumeration using a thread safe implementation
/// </summary>
/// <remarks>See https://stackoverflow.com/questions/47630824/is-c-sharp-linq-orderby-threadsafe-when-used-with-concurrentdictionarytkey-tva</remarks>
public static IEnumerable<KeyValuePair<TSource, TKey>> SafeEnumeration<TSource, TKey>(
this ConcurrentDictionary<TSource, TKey> source)
{
foreach (var kvp in source)
{
yield return kvp;
}
}
/// <summary>
/// Helper method to determine the right data normalization mode to use by default
/// </summary>

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -725,29 +725,6 @@ namespace QuantConnect
return exchange.GetPrimaryExchange(securityType, market).Code;
}
/// <summary>
/// Gets the exchange as single character representation.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Obsolete("This overload has not enough information to determine the exchange. " +
"Please use overload expecting a SecurityType and Market")]
public static string GetPrimaryExchangeAsSingleCharacter(this string exchange)
{
return exchange.GetPrimaryExchange().Code;
}
/// <summary>
/// Returns the main Exchange from the single character encoding.
/// </summary>
/// <param name="exchange"></param>
/// <returns></returns>
[Obsolete("This overload has not enough information to determine the exchange. " +
"Please use overload expecting a string, SecurityType and Market")]
public static Exchange GetPrimaryExchange(char exchange)
{
return exchange.ToString().GetPrimaryExchange();
}
/// <summary>
/// Gets the exchange as PrimaryExchange object.
/// </summary>

View File

@@ -18,6 +18,9 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using QuantConnect.Api;
using QuantConnect.Optimizer.Objectives;
using QuantConnect.Optimizer.Parameters;
using QuantConnect.Statistics;
namespace QuantConnect.Interfaces
{
@@ -169,6 +172,96 @@ namespace QuantConnect.Interfaces
/// <returns>BacktestList container for list of backtests</returns>
BacktestList ListBacktests(int projectId);
/// <summary>
/// Estimate optimization with the specified parameters via QuantConnect.com API
/// </summary>
/// <param name="projectId">Project ID of the project the optimization belongs to</param>
/// <param name="name">Name of the optimization</param>
/// <param name="target">Target of the optimization, see examples in <see cref="PortfolioStatistics"/></param>
/// <param name="targetTo">Target extremum of the optimization, for example "max" or "min"</param>
/// <param name="targetValue">Optimization target value</param>
/// <param name="strategy">Optimization strategy, <see cref="GridSearchOptimizationStrategy"/></param>
/// <param name="compileId">Optimization compile ID</param>
/// <param name="parameters">Optimization parameters</param>
/// <param name="constraints">Optimization constraints</param>
/// <returns>Estimate object from the API.</returns>
public Estimate EstimateOptimization(
int projectId,
string name,
string target,
string targetTo,
decimal? targetValue,
string strategy,
string compileId,
HashSet<OptimizationParameter> parameters,
IReadOnlyList<Constraint> constraints);
/// <summary>
/// Create an optimization with the specified parameters via QuantConnect.com API
/// </summary>
/// <param name="projectId">Project ID of the project the optimization belongs to</param>
/// <param name="name">Name of the optimization</param>
/// <param name="target">Target of the optimization, see examples in <see cref="PortfolioStatistics"/></param>
/// <param name="targetTo">Target extremum of the optimization, for example "max" or "min"</param>
/// <param name="targetValue">Optimization target value</param>
/// <param name="strategy">Optimization strategy, <see cref="GridSearchOptimizationStrategy"/></param>
/// <param name="compileId">Optimization compile ID</param>
/// <param name="parameters">Optimization parameters</param>
/// <param name="constraints">Optimization constraints</param>
/// <param name="estimatedCost">Estimated cost for optimization</param>
/// <param name="nodeType">Optimization node type</param>
/// <param name="parallelNodes">Number of parallel nodes for optimization</param>
/// <returns>BaseOptimization object from the API.</returns>
public BaseOptimization CreateOptimization(
int projectId,
string name,
string target,
string targetTo,
decimal? targetValue,
string strategy,
string compileId,
HashSet<OptimizationParameter> parameters,
IReadOnlyList<Constraint> constraints,
decimal estimatedCost,
string nodeType,
int parallelNodes);
/// <summary>
/// List all the optimizations for a project
/// </summary>
/// <param name="projectId">Project id we'd like to get a list of optimizations for</param>
/// <returns>A list of BaseOptimization objects, <see cref="BaseOptimization"/></returns>
public List<BaseOptimization> ListOptimizations(int projectId);
/// <summary>
/// Read an optimization
/// </summary>
/// <param name="optimizationId">Optimization id for the optimization we want to read</param>
/// <returns><see cref="Optimization"/></returns>
public Optimization ReadOptimization(string optimizationId);
/// <summary>
/// Abort an optimization
/// </summary>
/// <param name="optimizationId">Optimization id for the optimization we want to abort</param>
/// <returns><see cref="RestResponse"/></returns>
public RestResponse AbortOptimization(string optimizationId);
/// <summary>
/// Update an optimization
/// </summary>
/// <param name="optimizationId">Optimization id we want to update</param>
/// <param name="name">Name we'd like to assign to the optimization</param>
/// <returns><see cref="RestResponse"/></returns>
public RestResponse UpdateOptimization(string optimizationId, string name = null);
/// <summary>
/// Delete an optimization
/// </summary>
/// <param name="optimizationId">Optimization id for the optimization we want to delete</param>
/// <returns><see cref="RestResponse"/></returns>
public RestResponse DeleteOptimization(string optimizationId);
/// <summary>
/// Gets the logs of a specific live algorithm
/// </summary>
@@ -187,6 +280,25 @@ namespace QuantConnect.Interfaces
/// <returns>Link to the downloadable data.</returns>
DataLink ReadDataLink(string filePath, string organizationId);
/// <summary>
/// Get valid data entries for a given filepath from data/list
/// </summary>
/// <returns></returns>
DataList ReadDataDirectory(string filePath);
/// <summary>
/// Gets data prices from data/prices
/// </summary>
public DataPricesList ReadDataPrices(string organizationId);
/// <summary>
/// Read out the report of a backtest in the project id specified.
/// </summary>
/// <param name="projectId">Project id to read</param>
/// <param name="backtestId">Specific backtest id to read</param>
/// <returns><see cref="BacktestReport"/></returns>
public BacktestReport ReadBacktestReport(int projectId, string backtestId);
/// <summary>
/// Method to download and save the data purchased through QuantConnect
/// </summary>
@@ -194,6 +306,69 @@ namespace QuantConnect.Interfaces
/// <returns>A bool indicating whether the data was successfully downloaded or not.</returns>
bool DownloadData(string filePath, string organizationId);
/// <summary>
/// Create a new node in the organization, node configuration is defined by the
/// <see cref="SKU"/>
/// </summary>
/// <param name="name">The name of the new node</param>
/// <param name="organizationId">ID of the organization</param>
/// <param name="sku"><see cref="SKU"/> Object representing configuration</param>
/// <returns>Returns <see cref="CreatedNode"/> which contains API response and
/// <see cref="Node"/></returns>
public CreatedNode CreateNode(string name, string organizationId, SKU sku);
/// <summary>
/// Reads the nodes associated with the organization, creating a
/// <see cref="NodeList"/> for the response
/// </summary>
/// <param name="organizationId">ID of the organization</param>
/// <returns><see cref="NodeList"/> containing Backtest, Research, and Live Nodes</returns>
public NodeList ReadNodes(string organizationId);
/// <summary>
/// Update an organizations node with a new name
/// </summary>
/// <param name="nodeId">The node ID of the node you want to update</param>
/// <param name="newName">The new name for that node</param>
/// <param name="organizationId">ID of the organization</param>
/// <returns><see cref="RestResponse"/> containing success response and errors</returns>
public RestResponse UpdateNode(string nodeId, string newName, string organizationId);
/// <summary>
/// Delete a node from an organization, requires node ID.
/// </summary>
/// <param name="nodeId">The node ID of the node you want to delete</param>
/// <param name="organizationId">ID of the organization</param>
/// <returns><see cref="RestResponse"/> containing success response and errors</returns>
public RestResponse DeleteNode(string nodeId, string organizationId);
/// <summary>
/// Stop a running node in a organization
/// </summary>
/// <param name="nodeId">The node ID of the node you want to stop</param>
/// <param name="organizationId">ID of the organization</param>
/// <returns><see cref="RestResponse"/> containing success response and errors</returns>
public RestResponse StopNode(string nodeId, string organizationId);
/// <summary>
/// Will read the organization account status
/// </summary>
/// <param name="organizationId">The target organization id, if null will return default organization</param>
public Account ReadAccount(string organizationId = null);
/// <summary>
/// Get a list of organizations tied to this account
/// </summary>
/// <returns></returns>
public List<Organization> ListOrganizations();
/// <summary>
/// Fetch organization data from web API
/// </summary>
/// <param name="organizationId"></param>
/// <returns></returns>
public Organization ReadOrganization(string organizationId = null);
/// <summary>
/// Create a new live algorithm for a logged in user.
/// </summary>

View File

@@ -17,6 +17,8 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using QuantConnect.Util;
using System;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace QuantConnect.Optimizer.Objectives
{
@@ -29,7 +31,7 @@ namespace QuantConnect.Optimizer.Objectives
/// <summary>
/// The target comparison operation, eg. 'Greater'
/// </summary>
[JsonProperty("operator")]
[JsonProperty("operator"), JsonConverter(typeof(StringEnumConverter), typeof(DefaultNamingStrategy))]
public ComparisonOperatorTypes Operator { get; }
/// <summary>

View File

@@ -16,7 +16,7 @@
namespace QuantConnect.Optimizer.Objectives
{
/// <summary>
/// Defines standard maximization strategy, i.e. right operand is great than left
/// Defines standard maximization strategy, i.e. right operand is greater than left
/// </summary>
public class Maximization : Extremum
{

View File

@@ -0,0 +1,43 @@
/*
* 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.
*/
namespace QuantConnect.Optimizer
{
/// <summary>
/// The different optimization status
/// </summary>
public enum OptimizationStatus
{
/// <summary>
/// Just created and not running optimization
/// </summary>
New,
/// <summary>
/// We failed or we were aborted
/// </summary>
Aborted,
/// <summary>
/// We are running
/// </summary>
Running,
/// <summary>
/// Optimization job has completed
/// </summary>
Completed
}
}

View File

@@ -16,12 +16,15 @@
using System.Linq;
using QuantConnect.Util;
using System.Collections.Generic;
using Newtonsoft.Json;
using QuantConnect.Api;
namespace QuantConnect.Optimizer.Parameters
{
/// <summary>
/// Represents a single combination of optimization parameters
/// </summary>
[JsonConverter(typeof(ParameterSetJsonConverter))]
public class ParameterSet
{
/// <summary>
@@ -29,22 +32,24 @@ namespace QuantConnect.Optimizer.Parameters
/// </summary>
/// <remarks>Internal id, useful for the optimization strategy to id each generated parameter sets,
/// even before there is any backtest id</remarks>
[JsonProperty(PropertyName = "id")]
public int Id { get; }
/// <summary>
/// Represent a combination as key value of parameters, i.e. order doesn't matter
/// </summary>
public IReadOnlyDictionary<string, string> Value;
[JsonProperty(PropertyName = "value", NullValueHandling = NullValueHandling.Ignore)]
public IReadOnlyDictionary<string, string> Value { get; }
/// <summary>
/// Creates an instance of <see cref="ParameterSet"/> based on new combination of optimization parameters
/// </summary>
/// <param name="id">Unique identifier</param>
/// <param name="arguments">Combination of optimization parameters</param>
public ParameterSet(int id, Dictionary<string, string> arguments)
/// <param name="value">Combination of optimization parameters</param>
public ParameterSet(int id, Dictionary<string, string> value)
{
Id = id;
Value = arguments.ToReadOnlyDictionary();
Value = value?.ToReadOnlyDictionary();
}
/// <summary>

View File

@@ -31,7 +31,7 @@ namespace QuantConnect.Orders.Fees
/// <remarks>Default value is $0.0015 per share</remarks>
public AtreyuFeeModel(decimal? feesPerShare = null)
{
_feesPerShare = feesPerShare ?? 0.0015m;
_feesPerShare = feesPerShare ?? 0.0035m;
}
/// <summary>

View File

@@ -109,7 +109,7 @@ namespace QuantConnect.Orders.Fees
if (market == Market.Globex || market == Market.NYMEX
|| market == Market.CBOT || market == Market.ICE
|| market == Market.CFE || market == Market.COMEX
|| market == Market.CME)
|| market == Market.CME || market == Market.HKFE)
{
// just in case...
market = Market.USA;

View File

@@ -72,6 +72,8 @@ namespace QuantConnect.Orders.Fees
// limit order posted to the order book
unitPrice = ((LimitOrder)order).LimitPrice;
}
unitPrice *= security.SymbolProperties.ContractMultiplier;
var fee = TakerTier1CryptoFee;
@@ -104,7 +106,7 @@ namespace QuantConnect.Orders.Fees
CurrencyPairUtil.DecomposeCurrencyPair(security.Symbol, out actualBaseCurrency, out actualQuoteCurrency);
return new OrderFee(new CashAmount(
unitPrice * order.AbsoluteQuantity * fee,
isBuy ? unitPrice * order.AbsoluteQuantity * fee : 1 * order.AbsoluteQuantity * fee,
isBuy ? actualQuoteCurrency : actualBaseCurrency));
}
}

View File

@@ -37,7 +37,6 @@
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.10" />
<PackageReference Include="CloneExtensions" Version="1.3.0" />
<PackageReference Include="DotNetZip" Version="1.13.3" />
<PackageReference Include="fasterflect" Version="3.0.0" />
<PackageReference Include="MathNet.Numerics" Version="4.15.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -26,8 +26,13 @@ namespace QuantConnect.Scheduling
/// </summary>
public class TimeMonitor : IDisposable
{
private readonly List<TimeConsumer> _timeConsumers;
private readonly Timer _timer;
/// <summary>
/// List to store the coming TimeConsumer objects
/// </summary>
/// <remarks>This field is protected because it's used in a test class
/// in `IsolatorLimitResultProviderTests.cs</remarks>
protected readonly List<TimeConsumer> TimeConsumers;
/// <summary>
/// Returns the number of time consumers currently being monitored
@@ -36,9 +41,9 @@ namespace QuantConnect.Scheduling
{
get
{
lock (_timeConsumers)
lock (TimeConsumers)
{
return _timeConsumers.Count;
return TimeConsumers.Count;
}
}
}
@@ -48,48 +53,69 @@ namespace QuantConnect.Scheduling
/// </summary>
public TimeMonitor(int monitorIntervalMs = 100)
{
_timeConsumers = new List<TimeConsumer>();
TimeConsumers = new List<TimeConsumer>();
_timer = new Timer(state =>
{
lock (_timeConsumers)
lock (TimeConsumers)
{
_timeConsumers.RemoveAll(time => time.Finished);
RemoveAll();
foreach (var consumer in _timeConsumers)
foreach (var consumer in TimeConsumers)
{
if (consumer.NextTimeRequest == null)
{
// first time, for performance we register this here and not the time consumer
consumer.NextTimeRequest = consumer.TimeProvider.GetUtcNow().AddMinutes(1);
}
else if (consumer.TimeProvider.GetUtcNow() >= consumer.NextTimeRequest)
{
// each minute request additional time from the isolator
consumer.NextTimeRequest = consumer.NextTimeRequest.Value.AddMinutes(1);
try
{
// this will notify the isolator that we've exceed the limits
consumer.IsolatorLimitProvider.RequestAdditionalTime(minutes: 1);
}
catch
{
// pass
}
}
ProcessConsumer(consumer);
}
}
}, null, monitorIntervalMs, monitorIntervalMs);
}
/// <summary>
/// Process the TimeConsumer object in TimeConsumers list
/// </summary>
/// <param name="consumer">The TimeConsumer object to be processed</param>
/// <remarks>This method is protected because it's overrode by a test class
/// in `IsolatorLimitResultProviderTests.cs`</remarks>
protected virtual void ProcessConsumer(TimeConsumer consumer)
{
if (consumer.NextTimeRequest == null)
{
// first time, for performance we register this here and not the time consumer
consumer.NextTimeRequest = consumer.TimeProvider.GetUtcNow().AddMinutes(1);
}
else if (consumer.TimeProvider.GetUtcNow() >= consumer.NextTimeRequest)
{
// each minute request additional time from the isolator
consumer.NextTimeRequest = consumer.NextTimeRequest.Value.AddMinutes(1);
try
{
// this will notify the isolator that we've exceed the limits
consumer.IsolatorLimitProvider.RequestAdditionalTime(minutes: 1);
}
catch
{
// pass
}
}
}
/// <summary>
/// Remove all TimeConsumer objects where the `Finished` field is marked as true
/// </summary>
/// <remarks>This method is protected because it's overrode by a test class in
/// `IsolatorLimitResultProviderTests.cs`</remarks>
protected virtual void RemoveAll()
{
TimeConsumers.RemoveAll(time => time.Finished);
}
/// <summary>
/// Adds a new time consumer element to be monitored
/// </summary>
/// <param name="consumer">Time consumer instance</param>
public void Add(TimeConsumer consumer)
{
lock (_timeConsumers)
lock (TimeConsumers)
{
_timeConsumers.Add(consumer);
TimeConsumers.Add(consumer);
}
}

View File

@@ -19,6 +19,7 @@ using QuantConnect.Orders.Fees;
using QuantConnect.Orders.Fills;
using QuantConnect.Orders.Slippage;
using Python.Runtime;
using QuantConnect.Data.Market;
using QuantConnect.Util;
namespace QuantConnect.Securities.Future
@@ -27,7 +28,7 @@ namespace QuantConnect.Securities.Future
/// Futures Security Object Implementation for Futures Assets
/// </summary>
/// <seealso cref="Security"/>
public class Future : Security, IDerivativeSecurity
public class Future : Security, IDerivativeSecurity, IContinuousSecurity
{
/// <summary>
/// The default number of days required to settle a futures sale
@@ -167,6 +168,14 @@ namespace QuantConnect.Securities.Future
get; set;
}
/// <summary>
/// Gets or sets the currently mapped symbol for the security
/// </summary>
public Symbol Mapped
{
get; set;
}
/// <summary>
/// Gets or sets the contract filter
/// </summary>

View File

@@ -0,0 +1,28 @@
/*
* 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.
*/
namespace QuantConnect.Securities
{
/// <summary>
/// A continuous security that get's mapped during his life
/// </summary>
public interface IContinuousSecurity
{
/// <summary>
/// Gets or sets the currently mapped symbol for the security
/// </summary>
Symbol Mapped { get; set; }
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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.
*/
namespace QuantConnect.Statistics
{
/// <summary>
/// PerformanceMetrics contains the names of the various performance metrics used for evaluation purposes.
/// </summary>
public static class PerformanceMetrics
{
public const string Alpha = "Alpha";
public const string AnnualStandardDeviation = "Annual Standard Deviation";
public const string AnnualVariance = "Annual Variance";
public const string AverageLoss = "Average Loss";
public const string AverageWin = "Average Win";
public const string Beta = "Beta";
public const string CompoundingAnnualReturn = "Compounding Annual Return";
public const string Drawdown = "Drawdown";
public const string EstimatedStrategyCapacity = "Estimated Strategy Capacity";
public const string Expectancy = "Expectancy";
public const string InformationRatio = "Information Ratio";
public const string LossRate = "Loss Rate";
public const string NetProfit = "Net Profit";
public const string ProbabilisticSharpeRatio = "Probabilistic Sharpe Ratio";
public const string ProfitLossRatio = "Profit-Loss Ratio";
public const string SharpeRatio = "Sharpe Ratio";
public const string TotalFees = "Total Fees";
public const string TotalTrades = "Total Trades";
public const string TrackingError = "Tracking Error";
public const string TreynorRatio = "Treynor Ratio";
public const string WinRate = "Win Rate";
public const string LowestCapacityAsset = "Lowest Capacity Asset";
}
}

View File

@@ -174,28 +174,28 @@ namespace QuantConnect.Statistics
return new Dictionary<string, string>
{
{ "Total Trades", totalTransactions.ToStringInvariant() },
{ "Average Win", Math.Round(totalPerformance.PortfolioStatistics.AverageWinRate.SafeMultiply100(), 2).ToStringInvariant() + "%" },
{ "Average Loss", Math.Round(totalPerformance.PortfolioStatistics.AverageLossRate.SafeMultiply100(), 2).ToStringInvariant() + "%" },
{ "Compounding Annual Return", Math.Round(totalPerformance.PortfolioStatistics.CompoundingAnnualReturn.SafeMultiply100(), 3).ToStringInvariant() + "%" },
{ "Drawdown", Math.Round(totalPerformance.PortfolioStatistics.Drawdown.SafeMultiply100(), 3).ToStringInvariant() + "%" },
{ "Expectancy", Math.Round(totalPerformance.PortfolioStatistics.Expectancy, 3).ToStringInvariant() },
{ "Net Profit", Math.Round(totalPerformance.PortfolioStatistics.TotalNetProfit.SafeMultiply100(), 3).ToStringInvariant() + "%"},
{ "Sharpe Ratio", Math.Round((double)totalPerformance.PortfolioStatistics.SharpeRatio, 3).ToStringInvariant() },
{ "Probabilistic Sharpe Ratio", Math.Round(totalPerformance.PortfolioStatistics.ProbabilisticSharpeRatio.SafeMultiply100(), 3).ToStringInvariant() + "%"},
{ "Loss Rate", Math.Round(totalPerformance.PortfolioStatistics.LossRate.SafeMultiply100()).ToStringInvariant() + "%" },
{ "Win Rate", Math.Round(totalPerformance.PortfolioStatistics.WinRate.SafeMultiply100()).ToStringInvariant() + "%" },
{ "Profit-Loss Ratio", Math.Round(totalPerformance.PortfolioStatistics.ProfitLossRatio, 2).ToStringInvariant() },
{ "Alpha", Math.Round((double)totalPerformance.PortfolioStatistics.Alpha, 3).ToStringInvariant() },
{ "Beta", Math.Round((double)totalPerformance.PortfolioStatistics.Beta, 3).ToStringInvariant() },
{ "Annual Standard Deviation", Math.Round((double)totalPerformance.PortfolioStatistics.AnnualStandardDeviation, 3).ToStringInvariant() },
{ "Annual Variance", Math.Round((double)totalPerformance.PortfolioStatistics.AnnualVariance, 3).ToStringInvariant() },
{ "Information Ratio", Math.Round((double)totalPerformance.PortfolioStatistics.InformationRatio, 3).ToStringInvariant() },
{ "Tracking Error", Math.Round((double)totalPerformance.PortfolioStatistics.TrackingError, 3).ToStringInvariant() },
{ "Treynor Ratio", Math.Round((double)totalPerformance.PortfolioStatistics.TreynorRatio, 3).ToStringInvariant() },
{ "Total Fees", "$" + totalFees.ToStringInvariant("0.00") },
{ "Estimated Strategy Capacity", "$" + capacity.RoundToSignificantDigits(2).ToStringInvariant() },
{ "Lowest Capacity Asset", lowestCapacitySymbol != Symbol.Empty ? lowestCapacitySymbol.ID.ToString() : "" },
{ PerformanceMetrics.TotalTrades, totalTransactions.ToStringInvariant() },
{ PerformanceMetrics.AverageWin, Math.Round(totalPerformance.PortfolioStatistics.AverageWinRate.SafeMultiply100(), 2).ToStringInvariant() + "%" },
{ PerformanceMetrics.AverageLoss, Math.Round(totalPerformance.PortfolioStatistics.AverageLossRate.SafeMultiply100(), 2).ToStringInvariant() + "%" },
{ PerformanceMetrics.CompoundingAnnualReturn, Math.Round(totalPerformance.PortfolioStatistics.CompoundingAnnualReturn.SafeMultiply100(), 3).ToStringInvariant() + "%" },
{ PerformanceMetrics.Drawdown, Math.Round(totalPerformance.PortfolioStatistics.Drawdown.SafeMultiply100(), 3).ToStringInvariant() + "%" },
{ PerformanceMetrics.Expectancy, Math.Round(totalPerformance.PortfolioStatistics.Expectancy, 3).ToStringInvariant() },
{ PerformanceMetrics.NetProfit, Math.Round(totalPerformance.PortfolioStatistics.TotalNetProfit.SafeMultiply100(), 3).ToStringInvariant() + "%"},
{ PerformanceMetrics.SharpeRatio, Math.Round((double)totalPerformance.PortfolioStatistics.SharpeRatio, 3).ToStringInvariant() },
{ PerformanceMetrics.ProbabilisticSharpeRatio, Math.Round(totalPerformance.PortfolioStatistics.ProbabilisticSharpeRatio.SafeMultiply100(), 3).ToStringInvariant() + "%"},
{ PerformanceMetrics.LossRate, Math.Round(totalPerformance.PortfolioStatistics.LossRate.SafeMultiply100()).ToStringInvariant() + "%" },
{ PerformanceMetrics.WinRate, Math.Round(totalPerformance.PortfolioStatistics.WinRate.SafeMultiply100()).ToStringInvariant() + "%" },
{ PerformanceMetrics.ProfitLossRatio, Math.Round(totalPerformance.PortfolioStatistics.ProfitLossRatio, 2).ToStringInvariant() },
{ PerformanceMetrics.Alpha, Math.Round((double)totalPerformance.PortfolioStatistics.Alpha, 3).ToStringInvariant() },
{ PerformanceMetrics.Beta, Math.Round((double)totalPerformance.PortfolioStatistics.Beta, 3).ToStringInvariant() },
{ PerformanceMetrics.AnnualStandardDeviation, Math.Round((double)totalPerformance.PortfolioStatistics.AnnualStandardDeviation, 3).ToStringInvariant() },
{ PerformanceMetrics.AnnualVariance, Math.Round((double)totalPerformance.PortfolioStatistics.AnnualVariance, 3).ToStringInvariant() },
{ PerformanceMetrics.InformationRatio, Math.Round((double)totalPerformance.PortfolioStatistics.InformationRatio, 3).ToStringInvariant() },
{ PerformanceMetrics.TrackingError, Math.Round((double)totalPerformance.PortfolioStatistics.TrackingError, 3).ToStringInvariant() },
{ PerformanceMetrics.TreynorRatio, Math.Round((double)totalPerformance.PortfolioStatistics.TreynorRatio, 3).ToStringInvariant() },
{ PerformanceMetrics.TotalFees, "$" + totalFees.ToStringInvariant("0.00") },
{ PerformanceMetrics.EstimatedStrategyCapacity, "$" + capacity.RoundToSignificantDigits(2).ToStringInvariant() },
{ PerformanceMetrics.LowestCapacityAsset, lowestCapacitySymbol != Symbol.Empty ? lowestCapacitySymbol.ID.ToString() : "" },
};
}

View File

@@ -29,6 +29,12 @@ namespace QuantConnect
/// </summary>
public static class Time
{
/// <summary>
/// Allows specifying an offset to trigger the tradable date event
/// </summary>
/// <remarks>Useful for delaying the tradable date event until new auxiliary data is available to refresh map and factor files</remarks>
public static TimeSpan LiveAuxiliaryDataOffset { get; set; } = TimeSpan.FromHours(8);
/// <summary>
/// Provides a value far enough in the future the current computer hardware will have decayed :)
/// </summary>

View File

@@ -214,6 +214,25 @@ namespace QuantConnect.Util
}
}
/// <summary>
/// Will return all loaded types that are assignable to T type
/// </summary>
public IEnumerable<Type> GetExportedTypes<T>() where T : class
{
var type = typeof(T);
return _exportedTypes.Where(type1 =>
{
try
{
return type.IsAssignableFrom(type1);
}
catch
{
return false;
}
});
}
/// <summary>
/// Extension method to searches the composition container for an export that has a matching type name. This function
/// will first try to match on Type.AssemblyQualifiedName, then Type.FullName, and finally on Type.Name

View File

@@ -726,6 +726,7 @@ namespace QuantConnect.Util
case SecurityType.IndexOption:
if (isHourOrDaily)
{
// see TryParsePath: he knows tick type position is 3
var optionPath = symbol.Underlying.Value.ToLowerInvariant();
return $"{optionPath}_{date.Year}_{tickTypeString}_{symbol.ID.OptionStyle.OptionStyleToLower()}.zip";
}
@@ -735,6 +736,7 @@ namespace QuantConnect.Util
case SecurityType.FutureOption:
if (isHourOrDaily)
{
// see TryParsePath: he knows tick type position is 3
var futureOptionPath = symbol.ID.Symbol.ToLowerInvariant();
return $"{futureOptionPath}_{date.Year}_{tickTypeString}_{symbol.ID.OptionStyle.OptionStyleToLower()}.zip";
}
@@ -1013,7 +1015,15 @@ namespace QuantConnect.Util
var fileName = Path.GetFileNameWithoutExtension(filePath);
if (fileName.Contains("_"))
{
tickType = (TickType)Enum.Parse(typeof(TickType), fileName.Split('_')[1], true);
// example: 20140606_openinterest_american.zip
var tickTypePosition = 1;
if (resolution >= Resolution.Hour && symbol.SecurityType.IsOption())
{
// daily and hourly have the year too, example: aapl_2014_openinterest_american.zip
// see GenerateZipFileName he's creating these paths
tickTypePosition = 2;
}
tickType = (TickType)Enum.Parse(typeof(TickType), fileName.Split('_')[tickTypePosition], true);
}
dataType = GetDataType(resolution, tickType);

View File

@@ -97,7 +97,7 @@ namespace QuantConnect.Util
}
/// <summary>
/// Convert the input value to a value to be serialzied
/// Convert the input value to a value to be serialized
/// </summary>
/// <param name="value">The input value to be converted before serialziation</param>
/// <returns>A new instance of TResult that is to be serialzied</returns>

Some files were not shown because too many files have changed in this diff Show More