Compare commits

...

28 Commits
12710 ... 12876

Author SHA1 Message Date
Martin-Molinero
1ab1f90e27 Add research import QuantConnect.AlphaStream (#5918) 2021-09-09 15:12:42 -03:00
Martin-Molinero
bf2ef35ada Update readme.md 2021-09-09 12:14:46 -03:00
Colton Sellers
2001f9a181 Tradier Options History Support (#5912)
* Implement options support for history requests

* Address review
2021-09-09 11:19:12 -03:00
Stas Kotykhin
8026785116 Feature kraken brokerage setup (#5896)
* Kraken Brokerage initial setup

* Fix naming in config

* Add license messages

* Add fees for stablecoins

* add kraken databases

* Review fixes, tests added

* Remove redundant field and using

* add CanUpdateOrder & summary

* Remove null

* Change to equal

* complete xml comments
2021-09-08 12:49:13 -03:00
Ronit Jain
5083433f68 Inital brokerage setup commit (#5905) 2021-09-07 22:05:36 -03:00
quantify-cflynn
5d4f428906 Add ValueAreaVolumePercentage Parameter (#5908)
* Add ValueAreaVolumePercentage Parameter

Remove hard coding of parameter and set it to optional parameter for the user.

* Update TimeProfile.cs to include valueAreaVolumePercentage parameter

* Update TimeProfile definition in QCAlgorithm.Indicators.cs
2021-09-07 12:17:23 -03:00
Ricardo Andrés Marino Rojas
da60daa60d Market profile indicator (#5891)
* Create Market Profile indicator.

* - Requested changes in MarketProfile indicator made it.
- TimeProfile and VolumeProfile created and tested.
- tp_datatest.csv and vp_datatest.csv extracted from https://github.com/bfolkens/py-market-profile

* Final potential Market Profile Indicator.
All unit test made it and the indicator is passing all of them
Test cases made it with python library from GH issue

* Code styling request changes

* Minor suggestions

* Minor renaming tweaks

Co-authored-by: Martin-Molinero <martin@quantconnect.com>
2021-09-03 20:18:44 -03:00
Martin-Molinero
7d88b5040b Update readme.md 2021-09-03 19:20:11 -03:00
Martin-Molinero
d76106b444 Fix foundation build failure (#5902) 2021-09-03 17:41:58 -03:00
Martin-Molinero
de09ec0933 Update readme.md 2021-09-03 17:27:36 -03:00
Martin-Molinero
c3874bc618 Mapping Extensions will try get custom data from symbol (#5901) 2021-09-03 17:08:02 -03:00
Stefano Raggi
0e1e497fbf Update IBAutomater to v2.0.56 (#5900)
* Update IBAutomater to v2.0.55

* Update IBAutomater to v2.0.56
2021-09-03 10:31:22 -03:00
Martin-Molinero
8eb023e854 Remove duplicate market hours segments (#5897) 2021-09-02 19:09:51 -03:00
Martin-Molinero
b251cffc2f Alpha Streams improvements (#5887)
* Few improvements

- Alpha Streams algorithm will add target securities right away
- If algorithm is warming up PortfolioTargetCollection will emit not
  insight
- Fix local disk factor file provider to use local cache instead of data
  folder
- EWAS PCM will not emit targets for securities which have not been
  added by the algorithm yet, to avoid runtime exception

* Fix GetLastKnownPrice default order adding more unit tests
2021-09-01 13:12:26 -03:00
Stefano Raggi
1d904e716c Add new Market.CFE (#5391)
As most brokers use separate exchange codes for CBOE and CFE, we added the new Market.CFE (previously Market.CBOE was used for both exchanges). This change also avoids hacky code in symbol mappers.
2021-08-31 19:34:14 -03:00
Ronit Jain
df57428bd7 Fix zerodha async order event (#5878)
* Fix zerodha async order event

consider fillQuantity as total filled quantity

cover edge case of fully filled

fix async events received from zerodha

indentation fix

* Fix coding style

* keep order in only CachedOrderIDs
2021-08-30 19:32:40 -03:00
Stefano Raggi
9d734c4d8f Update IBGateway install path (#5885) 2021-08-30 17:11:12 -03:00
Martin-Molinero
765ce87df1 Remove unrequired link library (#5884) 2021-08-27 21:45:30 -03:00
Martin-Molinero
8a5766fa39 Update foundation base image to ubuntu 20.04 (#5882)
- Update amd64 and ARM foundatio base image to ubuntu 20.04
2021-08-27 19:47:20 -03:00
Martin-Molinero
933e5ce6ca Alpha Streams improvements (#5876)
* Alpha Streams improvements

- Warmup added securities so we can trigger an order right away
- Fix bug where AddSecurity returned a security which was not the one
  being used
- Fix bug where EWAS PCM would remove from a dictionary while iterating
  over it

* Fix unit tests

* Add QCAlgorithm.GetLastKnownPrices API

- Add new GetLastKnownPrices that will return the last known data point
  for all subscribed data types.
- Fix for MHDB GetDataTimeZone which was using an invalid entry key
  format for custom data.
- Fix for using GetLastKnownPrice/s to seed a security during creation,
  when it's not added in the Algorithm.Securities collection

* Adding more unit tests for GetLastKnownPrice

* Address reviews

- Refactor GetLastKnownPrice/s to perform a single history request for
  all data types
2021-08-27 13:50:45 -03:00
Gerardo Salazar
dc433493b7 Add support for specifying CoinAPI market to process (#5877)
* Add support for specifying CoinAPI market to process

* Address review: improve CoinAPI stability by making inputted market lowercase
2021-08-27 13:26:55 -03:00
Martin-Molinero
9acf68ad19 Bump pythonNet to 2.0.6 (#5881) 2021-08-26 18:01:05 -03:00
Martin-Molinero
5ebf451fb3 Fix for python SetHoldings precision loss (#5879)
- After https://github.com/QuantConnect/Lean/pull/5872 trading API
  changes numpy float64 was not converted correctly by pythonNet and
  used an int. Reverting API changes and adding regression test. This
  should be fixed at pythonNet layer
2021-08-25 15:25:39 -03:00
Gerardo Salazar
a4d49c05ca Adds ETF(...) to UniverseDefinitions (#5873)
* Adds ETF(...) to UniverseDefinitions

  * Adds ETF constituents universe framework regression algorithm
    for C#/Python

* Address review: adds test cases for ticker/Symbol ETF universe additions

  * Fixes bug where null Market would result in null dereference exception

* Address review: add missing Index tests

* Address review: don't hardcode market when creating constituent universe

  * Uses Brokerage Model's default markets collection to determine
    the market for the given security type

* Address review: restore QC500 and DollarVolume.Top(...)

  * Restores algorithms related to both helper universe
    definition methods

* Address review: remove copy to output directory for python algos

* Add example algorithms for ETF constituent universes using custom RSI alpha model

* Address review: adjust algorithm to use cache + algo RSI & clean up code

* Address review: make ETF Constituent RSI Alpha Model algo a regression test

* Address review: increase trade count and remove single trade logic
2021-08-25 11:22:31 -03:00
Martin-Molinero
aaba566954 Alpha Streams Improvements. Python Imports (#5874)
* Order handling improvements

- Execution model will only trigger market order if they are above the
  minimum order margin portfolio percetage value
- SecurityCache.Reset is complete

* Python Import fixes

- Add regression test for ImmediateExecutionModel minimum order margin
  check
2021-08-24 11:15:48 -03:00
Martin-Molinero
bf28a1d313 Add basic template Atreyu algorithm (#5872)
* Add basic template Atreyu algorithm

- Add C# and Python basic template atreyu algorithm. Show casing how to
  specify exchange to execute in different ways.
- Adjust trading API to allow specifying order properties to use

* Lean Exchange improvements

- Rename PrimaryExchange to Exchange
- OrderPropeties will use Exchange enum instead of string
- Adding BSE exchange value

* Regression tests fixes
2021-08-23 18:24:44 -03:00
Julio
85a4d3364b Add prefix "oanda-" to access-token (#5870)
Add prefix "oanda-" to account-id
2021-08-23 10:55:31 -03:00
IlshatGaripov
eccca2c029 Fix for Trailing Stop Risk Management Model (#5791)
* To fix the referenced issue

* Fixing up TrailingStopRiskManagementModel

* Fix-ups to address review

* Impl. tests + relevant improvements

* Minor logic improvement at first dictionary update

* Regression test small fix

* Adds explicit 'D' suffix for numbers in test case double arr

* Use integer values in test cases

* Removes failing testcases in MaximumDrawdownPercentPerSecurityTests (!) & renaming

* Revert "Removes failing testcases in MaximumDrawdownPercentPerSecurityTests (!) & renaming"

This reverts commit f9cd279f8c.

* Fix up for failing test cases
2021-08-20 15:14:36 -03:00
180 changed files with 5628 additions and 1558 deletions

View File

@@ -17,6 +17,8 @@ using System.Linq;
using QuantConnect.Data;
using QuantConnect.Orders;
using QuantConnect.Interfaces;
using QuantConnect.Brokerages;
using QuantConnect.Securities;
using System.Collections.Generic;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Data.Custom.AlphaStreams;
@@ -44,6 +46,9 @@ namespace QuantConnect.Algorithm.CSharp
Settings.MinimumOrderMarginPortfolioPercentage = 0.01m;
SetPortfolioConstruction(new EqualWeightingAlphaStreamsPortfolioConstructionModel());
SetSecurityInitializer(new BrokerageModelSecurityInitializer(new DefaultBrokerageModel(),
new FuncSecuritySeeder(GetLastKnownPrices)));
foreach (var alphaId in new [] { "623b06b231eb1cc1aa3643a46", "9fc8ef73792331b11dbd5429a" })
{
AddData<AlphaStreamsPortfolioState>(alphaId);
@@ -58,24 +63,7 @@ namespace QuantConnect.Algorithm.CSharp
{
foreach (var portfolioState in data.Get<AlphaStreamsPortfolioState>().Values)
{
var alphaId = portfolioState.Symbol;
var currentSymbols = _symbolsPerAlpha[alphaId];
var newSymbols = new HashSet<Symbol>(currentSymbols.Count);
foreach (var symbol in portfolioState.PositionGroups?.SelectMany(positionGroup => positionGroup.Positions).Select(state => state.Symbol) ?? Enumerable.Empty<Symbol>())
{
// only add it if it's not used by any alpha (already added check)
if (newSymbols.Add(symbol) && !UsedBySomeAlpha(symbol))
{
AddSecurity(symbol, resolution: UniverseSettings.Resolution);
}
}
_symbolsPerAlpha[alphaId] = newSymbols;
foreach (var symbol in currentSymbols.Where(symbol => !UsedBySomeAlpha(symbol)))
{
RemoveSecurity(symbol);
}
ProcessPortfolioState(portfolioState);
}
}
@@ -91,7 +79,12 @@ namespace QuantConnect.Algorithm.CSharp
{
if (addedSecurity.Symbol.IsCustomDataType<AlphaStreamsPortfolioState>())
{
_symbolsPerAlpha[addedSecurity.Symbol] = new HashSet<Symbol>();
if (!_symbolsPerAlpha.ContainsKey(addedSecurity.Symbol))
{
_symbolsPerAlpha[addedSecurity.Symbol] = new HashSet<Symbol>();
}
// warmup alpha state, adding target securities
ProcessPortfolioState(addedSecurity.Cache.GetData<AlphaStreamsPortfolioState>());
}
}
@@ -103,6 +96,36 @@ namespace QuantConnect.Algorithm.CSharp
return _symbolsPerAlpha.Any(pair => pair.Value.Contains(asset));
}
private void ProcessPortfolioState(AlphaStreamsPortfolioState portfolioState)
{
if (portfolioState == null)
{
return;
}
var alphaId = portfolioState.Symbol;
if (!_symbolsPerAlpha.TryGetValue(alphaId, out var currentSymbols))
{
_symbolsPerAlpha[alphaId] = currentSymbols = new HashSet<Symbol>();
}
var newSymbols = new HashSet<Symbol>(currentSymbols.Count);
foreach (var symbol in portfolioState.PositionGroups?.SelectMany(positionGroup => positionGroup.Positions).Select(state => state.Symbol) ?? Enumerable.Empty<Symbol>())
{
// only add it if it's not used by any alpha (already added check)
if (newSymbols.Add(symbol) && !UsedBySomeAlpha(symbol))
{
AddSecurity(symbol, resolution: UniverseSettings.Resolution, extendedMarketHours: UniverseSettings.ExtendedMarketHours);
}
}
_symbolsPerAlpha[alphaId] = newSymbols;
foreach (var symbol in currentSymbols.Where(symbol => !UsedBySomeAlpha(symbol)))
{
RemoveSecurity(symbol);
}
}
/// <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

@@ -47,17 +47,17 @@ namespace QuantConnect.Algorithm.CSharp
public override Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Trades", "2"},
{"Average Win", "0%"},
{"Average Loss", "-0.84%"},
{"Average Win", "0.01%"},
{"Average Loss", "0.00%"},
{"Compounding Annual Return", "-78.502%"},
{"Drawdown", "3.100%"},
{"Expectancy", "-1"},
{"Expectancy", "7.797"},
{"Net Profit", "-1.134%"},
{"Sharpe Ratio", "-2.456"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Loss Rate", "50%"},
{"Win Rate", "50%"},
{"Profit-Loss Ratio", "16.59"},
{"Alpha", "0.008"},
{"Beta", "1.012"},
{"Annual Standard Deviation", "0.343"},

View File

@@ -27,7 +27,6 @@ namespace QuantConnect.Algorithm.CSharp
/// </summary>
public class AlphaStreamsWithHoldingsBasicTemplateAlgorithm : AlphaStreamsBasicTemplateAlgorithm
{
private decimal _initialCash = 100000;
private decimal _expectedSpyQuantity;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
@@ -36,33 +35,33 @@ namespace QuantConnect.Algorithm.CSharp
{
SetStartDate(2018, 04, 04);
SetEndDate(2018, 04, 06);
SetCash(_initialCash);
SetCash(100000);
SetExecution(new ImmediateExecutionModel());
UniverseSettings.Resolution = Resolution.Hour;
Settings.MinimumOrderMarginPortfolioPercentage = 0.01m;
Settings.MinimumOrderMarginPortfolioPercentage = 0.001m;
SetPortfolioConstruction(new EqualWeightingAlphaStreamsPortfolioConstructionModel());
// AAPL should be liquidated since it's not hold by the alpha
// This is handled by the PCM
var aapl = AddEquity("AAPL", Resolution.Hour);
aapl.Holdings.SetHoldings(100, 10);
aapl.Holdings.SetHoldings(40, 10);
// SPY will be bought following the alpha streams portfolio
// This is handled by the PCM + Execution Model
var spy = AddEquity("SPY", Resolution.Hour);
spy.Holdings.SetHoldings(100, -10);
spy.Holdings.SetHoldings(246, -10);
AddData<AlphaStreamsPortfolioState>("94d820a93fff127fa46c15231d");
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (_expectedSpyQuantity == 0 && orderEvent.Symbol == "SPY")
if (_expectedSpyQuantity == 0 && orderEvent.Symbol == "SPY" && orderEvent.Status == OrderStatus.Filled)
{
var security = Securities["SPY"];
var priceInAccountCurrency = security.AskPrice * security.QuoteCurrency.ConversionRate;
_expectedSpyQuantity = (_initialCash * (1 - Settings.FreePortfolioValuePercentage) - priceInAccountCurrency) / priceInAccountCurrency;
var priceInAccountCurrency = Portfolio.CashBook.ConvertToAccountCurrency(security.AskPrice, security.QuoteCurrency.Symbol);
_expectedSpyQuantity = (Portfolio.TotalPortfolioValue - Settings.FreePortfolioValue) / priceInAccountCurrency;
_expectedSpyQuantity = _expectedSpyQuantity.DiscretelyRoundBy(1, MidpointRounding.ToZero);
}
@@ -76,7 +75,8 @@ namespace QuantConnect.Algorithm.CSharp
throw new Exception("We should no longer hold AAPL since the alpha does not");
}
if (Securities["SPY"].Holdings.Quantity != _expectedSpyQuantity)
// we allow some padding for small price differences
if (Math.Abs(Securities["SPY"].Holdings.Quantity - _expectedSpyQuantity) > _expectedSpyQuantity * 0.03m)
{
throw new Exception($"Unexpected SPY holdings. Expected {_expectedSpyQuantity} was {Securities["SPY"].Holdings.Quantity}");
}
@@ -98,17 +98,17 @@ namespace QuantConnect.Algorithm.CSharp
public override Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Trades", "2"},
{"Average Win", "0%"},
{"Average Loss", "-1.03%"},
{"Average Win", "0.01%"},
{"Average Loss", "0.00%"},
{"Compounding Annual Return", "-87.617%"},
{"Drawdown", "3.100%"},
{"Expectancy", "-1"},
{"Expectancy", "8.518"},
{"Net Profit", "-1.515%"},
{"Sharpe Ratio", "-2.45"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Loss Rate", "50%"},
{"Win Rate", "50%"},
{"Profit-Loss Ratio", "18.04"},
{"Alpha", "0.008"},
{"Beta", "1.015"},
{"Annual Standard Deviation", "0.344"},

View File

@@ -0,0 +1,130 @@
/*
* 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 QuantConnect.Brokerages;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic template algorithm for the Atreyu brokerage
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="using quantconnect" />
/// <meta name="tag" content="trading and orders" />
public class BasicTemplateAtreyuAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
/// <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, 07);
SetEndDate(2013, 10, 11);
SetCash(100000);
SetBrokerageModel(BrokerageName.Atreyu);
AddEquity("SPY", Resolution.Minute);
DefaultOrderProperties = new AtreyuOrderProperties
{
// Can specify the default exchange to execute an order on.
// If not specified will default to the primary exchange
Exchange = Exchange.NASDAQ,
// Currently only support order for the day
TimeInForce = TimeInForce.Day
};
}
/// <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 (!Portfolio.Invested)
{
// will set 25% of our buying power with a market order that will be routed to exchange set in the default order properties (NASDAQ)
SetHoldings("SPY", 0.25m);
// will increase our SPY holdings to 50% of our buying power with a market order that will be routed to ARCA
SetHoldings("SPY", 0.50m, orderProperties: new AtreyuOrderProperties { Exchange = Exchange.ARCA });
Debug("Purchased SPY!");
}
}
/// <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%"},
{"Compounding Annual Return", "93.443%"},
{"Drawdown", "1.100%"},
{"Expectancy", "0"},
{"Net Profit", "0.847%"},
{"Sharpe Ratio", "6.515"},
{"Probabilistic Sharpe Ratio", "67.535%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0.11"},
{"Annual Variance", "0.012"},
{"Information Ratio", "6.515"},
{"Tracking Error", "0.11"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.52"},
{"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"},
{"Portfolio Turnover", "0.124"},
{"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", "cb542eaaeab5eac3bcae5d915ded30da"}
};
}
}

View File

@@ -1,53 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Data.UniverseSelection;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic template algorithm which showcases <see cref="ConstituentsUniverse"/> simple use case
/// </summary>
public class BasicTemplateConstituentUniverseAlgorithm : QCAlgorithm
{
/// <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, 07);
SetEndDate(2013, 10, 11);
// by default will use algorithms UniverseSettings
AddUniverse(Universe.Constituent.Steel());
// we specify the UniverseSettings it should use
AddUniverse(Universe.Constituent.AggressiveGrowth(
new UniverseSettings(Resolution.Hour,
2,
false,
false,
UniverseSettings.MinimumTimeInUniverse)));
SetAlpha(new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromDays(1)));
SetExecution(new ImmediateExecutionModel());
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
}
}
}

View File

@@ -82,7 +82,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <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 };
public virtual 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

View File

@@ -13,16 +13,9 @@
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Orders;
using QuantConnect.Interfaces;
using QuantConnect.Data;
using QuantConnect.Orders;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
@@ -47,15 +40,14 @@ namespace QuantConnect.Algorithm.CSharp
// Find more symbols here: http://quantconnect.com/data
// Equities Resolutions: Tick, Second, Minute, Hour, Daily.
AddEquity("UNIONBANK", Resolution.Second, Market.India);
//Set Order Prperties as per the requirements for order placement
DefaultOrderProperties = new ZerodhaOrderProperties(exchange: "nse");
DefaultOrderProperties = new IndiaOrderProperties(exchange: Exchange.NSE);
//override default productType value set in config.json if needed - order specific productType value
//DefaultOrderProperties = new ZerodhaOrderProperties(exchange: "nse",ZerodhaOrderProperties.KiteProductType.CNC);
//DefaultOrderProperties = new IndiaOrderProperties(exchange: Exchange.NSE, IndiaOrderProperties.IndiaProductType.CNC);
// General Debug statement for acknowledgement
Debug("Intialization Done");
}
/// <summary>
@@ -70,7 +62,6 @@ namespace QuantConnect.Algorithm.CSharp
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status.IsFill())

View File

@@ -35,7 +35,7 @@ namespace QuantConnect.Algorithm.CSharp
SetCash(100000); // Set Strategy Cash
// Add QC500 Universe
AddUniverse(Universe.Index.QC500);
AddUniverse(Universe.QC500);
}
}
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.Linq;
using QuantConnect.Interfaces;
using System.Collections.Generic;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm that will test that <see cref="IAlgorithmSettings.MinimumOrderMarginPortfolioPercentage"/>
/// is respected by the <see cref="ImmediateExecutionModel"/>
/// </summary>
public class ImmediateExecutionModelMinimumOrderMarginRegressionAlgorithm : BasicTemplateFrameworkAlgorithm
{
public override void Initialize()
{
base.Initialize();
// this setting is the difference between doing 3 trades and > 60
Settings.MinimumOrderMarginPortfolioPercentage = 0.001m;
SetPortfolioConstruction(new CustomPortfolioConstructionModel(TimeKeeper));
}
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public override Language[] Languages { get; } = { Language.CSharp };
private class CustomPortfolioConstructionModel : EqualWeightingPortfolioConstructionModel
{
private ITimeKeeper _timeKeeper;
public CustomPortfolioConstructionModel(ITimeKeeper timeKeeper)
{
_timeKeeper = timeKeeper;
}
protected override Dictionary<Insight, double> DetermineTargetPercent(List<Insight> activeInsights)
{
var baseResult = base.DetermineTargetPercent(activeInsights);
// we generate some fake noise in the percentage allocation
var adjustPercentage = _timeKeeper.UtcTime.Minute % 2 == 0;
return baseResult.ToDictionary(pair => pair.Key, pair => adjustPercentage ? pair.Value - 0.001 : pair.Value);
}
}
}
}

View File

@@ -35,7 +35,7 @@
<DebugType>portable</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.5" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.6" />
<PackageReference Include="Accord" Version="3.6.0" />
<PackageReference Include="Accord.Fuzzy" Version="3.6.0" />
<PackageReference Include="Accord.MachineLearning" Version="3.6.0" />

View File

@@ -62,7 +62,7 @@ namespace QuantConnect.Algorithm.CSharp
_gdvd = QuantConnect.Symbol.Create("GDVD", SecurityType.Equity, Market.USA);
}
AddUniverse(new ETFConstituentsUniverse(_gdvd, UniverseSettings, FilterETFs));
AddUniverse(Universe.ETF(_gdvd, universeFilterFunc: FilterETFs));
}
private IEnumerable<Symbol> FilterETFs(IEnumerable<ETFConstituentData> constituents)

View File

@@ -52,7 +52,7 @@ namespace QuantConnect.Algorithm.CSharp
_spy = AddEquity("SPY", Resolution.Hour).Symbol;
_aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
AddUniverse(new ETFConstituentsUniverse(_spy, UniverseSettings, FilterETFs));
AddUniverse(Universe.ETF(_spy, universeFilterFunc: FilterETFs));
}
/// <summary>

View File

@@ -0,0 +1,249 @@
/*
* 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.Linq;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Tests ETF constituents universe selection with the algorithm framework models (Alpha, PortfolioConstruction, Execution)
/// </summary>
public class ETFConstituentUniverseFrameworkRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private List<ETFConstituentData> ConstituentData = new List<ETFConstituentData>();
/// <summary>
/// Initializes the algorithm, setting up the framework classes and ETF constituent universe settings
/// </summary>
public override void Initialize()
{
SetStartDate(2020, 12, 1);
SetEndDate(2021, 1, 31);
SetCash(100000);
SetAlpha(new ETFConstituentAlphaModel());
SetPortfolioConstruction(new ETFConstituentPortfolioModel());
SetExecution(new ETFConstituentExecutionModel());
var spy = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
UniverseSettings.Resolution = Resolution.Hour;
AddUniverse(Universe.ETF(spy, UniverseSettings, FilterETFConstituents));
}
/// <summary>
/// Filters ETF constituents
/// </summary>
/// <param name="constituents">ETF constituents</param>
/// <returns>ETF constituent Symbols that we want to include in the algorithm</returns>
public IEnumerable<Symbol> FilterETFConstituents(IEnumerable<ETFConstituentData> constituents)
{
var constituentData = constituents
.Where(x => (x.Weight ?? 0m) >= 0.001m)
.ToList();
ConstituentData = constituentData;
return constituentData
.Select(x => x.Symbol)
.ToList();
}
/// <summary>
/// no-op for performance
/// </summary>
public override void OnData(Slice data)
{
}
/// <summary>
/// Alpha model for ETF constituents, where we generate insights based on the weighting
/// of the ETF constituent
/// </summary>
private class ETFConstituentAlphaModel : IAlphaModel
{
public void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
}
/// <summary>
/// Creates new insights based on constituent data and their weighting
/// in their respective ETF
/// </summary>
public IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
var algo = (ETFConstituentUniverseFrameworkRegressionAlgorithm) algorithm;
foreach (var constituent in algo.ConstituentData)
{
if (!data.Bars.ContainsKey(constituent.Symbol) &&
!data.QuoteBars.ContainsKey(constituent.Symbol))
{
continue;
}
var insightDirection = constituent.Weight != null && constituent.Weight >= 0.01m
? InsightDirection.Up
: InsightDirection.Down;
yield return new Insight(
algorithm.UtcTime,
constituent.Symbol,
TimeSpan.FromDays(1),
InsightType.Price,
insightDirection,
1 * (double)insightDirection,
1.0,
weight: (double)(constituent.Weight ?? 0));
}
}
}
/// <summary>
/// Generates targets for ETF constituents, which will be set to the weighting
/// of the constituent in their respective ETF
/// </summary>
private class ETFConstituentPortfolioModel : IPortfolioConstructionModel
{
private bool _hasAdded;
/// <summary>
/// Securities changed, detects if we've got new additions to the universe
/// so that we don't try to trade every loop
/// </summary>
public void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
_hasAdded = changes.AddedSecurities.Count != 0;
}
/// <summary>
/// Creates portfolio targets based on the insights provided to us by the alpha model.
/// Emits portfolio targets setting the quantity to the weight of the constituent
/// in its respective ETF.
/// </summary>
public IEnumerable<IPortfolioTarget> CreateTargets(QCAlgorithm algorithm, Insight[] insights)
{
if (!_hasAdded)
{
yield break;
}
foreach (var insight in insights)
{
yield return new PortfolioTarget(insight.Symbol, (decimal) (insight.Weight ?? 0));
_hasAdded = false;
}
}
}
/// <summary>
/// Executes based on ETF constituent weighting
/// </summary>
private class ETFConstituentExecutionModel : IExecutionModel
{
/// <summary>
/// Liquidates if constituents have been removed from the universe
/// </summary>
public void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
foreach (var change in changes.RemovedSecurities)
{
algorithm.Liquidate(change.Symbol);
}
}
/// <summary>
/// Creates orders for constituents that attempts to add
/// the weighting of the constituent in our portfolio. The
/// resulting algorithm portfolio weight might not be equal
/// to the leverage of the ETF (1x, 2x, 3x, etc.)
/// </summary>
public void Execute(QCAlgorithm algorithm, IPortfolioTarget[] targets)
{
foreach (var target in targets)
{
algorithm.SetHoldings(target.Symbol, target.Quantity);
}
}
}
/// <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", "4"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "3.225%"},
{"Drawdown", "0.800%"},
{"Expectancy", "0"},
{"Net Profit", "0.520%"},
{"Sharpe Ratio", "1.518"},
{"Probabilistic Sharpe Ratio", "57.759%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.022"},
{"Beta", "0.101"},
{"Annual Standard Deviation", "0.022"},
{"Annual Variance", "0"},
{"Information Ratio", "-0.653"},
{"Tracking Error", "0.117"},
{"Treynor Ratio", "0.333"},
{"Total Fees", "$4.00"},
{"Estimated Strategy Capacity", "$1300000000.00"},
{"Lowest Capacity Asset", "AIG R735QTJ8XC9X"},
{"Fitness Score", "0.001"},
{"Kelly Criterion Estimate", "1.528"},
{"Kelly Criterion Probability Value", "0.091"},
{"Sortino Ratio", "4.929"},
{"Return Over Maximum Drawdown", "8.624"},
{"Portfolio Turnover", "0.001"},
{"Total Insights Generated", "1108"},
{"Total Insights Closed", "1080"},
{"Total Insights Analysis Completed", "1080"},
{"Long Insight Count", "277"},
{"Short Insight Count", "831"},
{"Long/Short Ratio", "33.33%"},
{"Estimated Monthly Alpha Value", "$4169774.3402"},
{"Total Accumulated Estimated Alpha Value", "$8322174.6207"},
{"Mean Population Estimated Insight Value", "$7705.7172"},
{"Mean Population Direction", "49.7222%"},
{"Mean Population Magnitude", "49.7222%"},
{"Rolling Averaged Population Direction", "56.0724%"},
{"Rolling Averaged Population Magnitude", "56.0724%"},
{"OrderListHash", "eb27e818f4a6609329a52feeb74bd554"}
};
}
}

View File

@@ -48,7 +48,7 @@ namespace QuantConnect.Algorithm.CSharp
_aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
_qqq = AddEquity("QQQ", Resolution.Daily).Symbol;
AddUniverse(new ETFConstituentsUniverse(_qqq, UniverseSettings, FilterETFs));
AddUniverse(Universe.ETF(_qqq, universeFilterFunc: FilterETFs));
}
private IEnumerable<Symbol> FilterETFs(IEnumerable<ETFConstituentData> constituents)

View File

@@ -0,0 +1,250 @@
/*
* 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.Linq;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Example algorithm demonstrating the usage of the RSI indicator
/// in combination with ETF constituents data to replicate the weighting
/// of the ETF's assets in our own account.
/// </summary>
public class ETFConstituentUniverseRSIAlphaModelAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
/// <summary>
/// Initialize 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(2020, 12, 1);
SetEndDate(2021, 1, 31);
SetCash(100000);
SetAlpha(new ConstituentWeightedRsiAlphaModel());
SetPortfolioConstruction(new InsightWeightingPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
var spy = AddEquity("SPY", Resolution.Hour).Symbol;
// We load hourly data for ETF constituents in this algorithm
UniverseSettings.Resolution = Resolution.Hour;
Settings.MinimumOrderMarginPortfolioPercentage = 0.01m;
AddUniverse(Universe.ETF(spy, UniverseSettings, FilterETFConstituents));
}
/// <summary>
/// Filters ETF constituents and adds the resulting Symbols to the ETF constituent universe
/// </summary>
/// <param name="constituents">ETF constituents, i.e. the components of the ETF and their weighting</param>
/// <returns>Symbols to add to universe</returns>
public IEnumerable<Symbol> FilterETFConstituents(IEnumerable<ETFConstituentData> constituents)
{
return constituents
.Where(x => x.Weight != null && x.Weight >= 0.001m)
.Select(x => x.Symbol);
}
/// <summary>
/// Alpha model making use of the RSI indicator and ETF constituent weighting to determine
/// which assets we should invest in and the direction of investment
/// </summary>
private class ConstituentWeightedRsiAlphaModel : AlphaModel
{
private Dictionary<Symbol, SymbolData> _rsiSymbolData = new Dictionary<Symbol, SymbolData>();
/// <summary>
/// Receives new data and emits new <see cref="Insight"/> instances
/// </summary>
/// <param name="algorithm">Algorithm</param>
/// <param name="data">Current data</param>
/// <returns>Enumerable of insights for assets to invest with a specific weight</returns>
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
// Cast first, and then access the constituents collection defined in our algorithm.
var algoConstituents = data.Bars.Keys
.Where(x => algorithm.Securities[x].Cache.HasData(typeof(ETFConstituentData)))
.Select(x => algorithm.Securities[x].Cache.GetData<ETFConstituentData>())
.ToList();
if (algoConstituents.Count == 0 || data.Bars.Count == 0)
{
// Don't do anything if we have no data we can work with
yield break;
}
var constituents = algoConstituents
.ToDictionary(x => x.Symbol, x => x);
foreach (var bar in data.Bars.Values)
{
if (!constituents.ContainsKey(bar.Symbol))
{
// Dealing with a manually added equity, which in this case is SPY
continue;
}
if (!_rsiSymbolData.ContainsKey(bar.Symbol))
{
// First time we're initializing the RSI.
// It won't be ready now, but it will be
// after 7 data points.
var constituent = constituents[bar.Symbol];
_rsiSymbolData[bar.Symbol] = new SymbolData(bar.Symbol, algorithm, constituent, 7);
}
}
// Let's make sure all RSI indicators are ready before we emit any insights.
var allReady = _rsiSymbolData.All(kvp => kvp.Value.Rsi.IsReady);
if (!allReady)
{
// We're still warming up the RSI indicators.
yield break;
}
foreach (var kvp in _rsiSymbolData)
{
var symbol = kvp.Key;
var symbolData = kvp.Value;
var averageLoss = symbolData.Rsi.AverageLoss.Current.Value;
var averageGain = symbolData.Rsi.AverageGain.Current.Value;
// If we've lost more than gained, then we think it's going to go down more
var direction = averageLoss > averageGain
? InsightDirection.Down
: InsightDirection.Up;
// Set the weight of the insight as the weight of the ETF's
// holding. The InsightWeightingPortfolioConstructionModel
// will rebalance our portfolio to have the same percentage
// of holdings in our algorithm that the ETF has.
yield return Insight.Price(
symbol,
TimeSpan.FromDays(1),
direction,
(double)(direction == InsightDirection.Down
? averageLoss
: averageGain),
weight: (double?) symbolData.Constituent.Weight);
}
}
}
/// <summary>
/// Helper class to access ETF constituent data and RSI indicators
/// for a single Symbol
/// </summary>
private class SymbolData
{
/// <summary>
/// Symbol this data belongs to
/// </summary>
public Symbol Symbol { get; }
/// <summary>
/// Symbol's constituent data for the ETF it belongs to
/// </summary>
public ETFConstituentData Constituent { get; }
/// <summary>
/// RSI indicator for the Symbol's price data
/// </summary>
public RelativeStrengthIndex Rsi { get; }
/// <summary>
/// Creates a new instance of SymbolData
/// </summary>
/// <param name="symbol">The symbol to add data for</param>
/// <param name="constituent">ETF constituent data</param>
/// <param name="period">RSI period</param>
public SymbolData(Symbol symbol, QCAlgorithm algorithm, ETFConstituentData constituent, int period)
{
Symbol = symbol;
Constituent = constituent;
Rsi = algorithm.RSI(symbol, period, MovingAverageType.Exponential, Resolution.Hour);
}
}
/// <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", "52"},
{"Average Win", "0.09%"},
{"Average Loss", "-0.05%"},
{"Compounding Annual Return", "3.919%"},
{"Drawdown", "0.500%"},
{"Expectancy", "0.080"},
{"Net Profit", "0.630%"},
{"Sharpe Ratio", "2.197"},
{"Probabilistic Sharpe Ratio", "67.639%"},
{"Loss Rate", "61%"},
{"Win Rate", "39%"},
{"Profit-Loss Ratio", "1.75"},
{"Alpha", "0.043"},
{"Beta", "-0.024"},
{"Annual Standard Deviation", "0.018"},
{"Annual Variance", "0"},
{"Information Ratio", "-0.522"},
{"Tracking Error", "0.133"},
{"Treynor Ratio", "-1.678"},
{"Total Fees", "$52.00"},
{"Estimated Strategy Capacity", "$430000000.00"},
{"Lowest Capacity Asset", "AAPL R735QTJ8XC9X"},
{"Fitness Score", "0.144"},
{"Kelly Criterion Estimate", "-2.61"},
{"Kelly Criterion Probability Value", "0.987"},
{"Sortino Ratio", "2.877"},
{"Return Over Maximum Drawdown", "6.437"},
{"Portfolio Turnover", "0.162"},
{"Total Insights Generated", "1076"},
{"Total Insights Closed", "1048"},
{"Total Insights Analysis Completed", "1048"},
{"Long Insight Count", "530"},
{"Short Insight Count", "546"},
{"Long/Short Ratio", "97.07%"},
{"Estimated Monthly Alpha Value", "$-378965.1"},
{"Total Accumulated Estimated Alpha Value", "$-756351.1"},
{"Mean Population Estimated Insight Value", "$-721.7091"},
{"Mean Population Direction", "45.8015%"},
{"Mean Population Magnitude", "45.8015%"},
{"Rolling Averaged Population Direction", "45.6662%"},
{"Rolling Averaged Population Magnitude", "45.6662%"},
{"OrderListHash", "f320b74a7bb7207f3f88f7fce9d0f286"}
};
}
}

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.Brokerages;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Orders;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This example demonstrates how to add options for a given underlying equity security. It also
/// shows how you can prefilter contracts easily based on strikes and expirations, and how you
/// can inspect the option chain to pick a specific option contract to trade.
/// </summary>
/// <meta name="tag" content="using data"/>
/// <meta name="tag" content="options"/>
/// <meta name="tag" content="filter selection"/>
public class SamcoBasicTemplateOptionsAlgorithm : QCAlgorithm
{
private const string UnderlyingTicker = "NIFTY";
public Symbol OptionSymbol;
public override void Initialize()
{
SetTimeZone(TimeZones.Kolkata);
SetBrokerageModel(BrokerageName.Samco, AccountType.Margin);
SetAccountCurrency(Currencies.INR);
var equity = AddEquity(UnderlyingTicker, market: Market.India);
var option = AddOption(equity.Symbol, market: Market.India);
OptionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for
// days. The following statements yield the same filtering criteria
.Expiration(0, 180));
// .Expiration(TimeSpan.Zero, TimeSpan.FromDays(180)));
}
/// <summary>
/// Event - v3.0 DATA EVENT HANDLER: (Pattern) Basic template for user to override for
/// receiving all subscription data in a single event
/// </summary>
/// <param name="slice">The current slice of data keyed by symbol string</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested && IsMarketOpen(OptionSymbol))
{
OptionChain chain;
if (slice.OptionChains.TryGetValue(OptionSymbol, out chain))
{
// we find at the money (ATM) put contract with farthest expiration
var atmContract = chain
.OrderByDescending(x => x.Expiry)
.ThenBy(x => Math.Abs(chain.Underlying.Price - x.Strike))
.ThenByDescending(x => x.Right)
.FirstOrDefault();
if (atmContract != null)
{
// if found, trade it
MarketOrder(atmContract.Symbol, 1);
MarketOnCloseOrder(atmContract.Symbol, -1);
}
}
}
}
/// <summary>
/// Order fill event handler. On an order fill update the resulting information is passed to
/// this method.
/// </summary>
/// <param name="orderEvent">Order event details containing details of the evemts</param>
/// <remarks>
/// This method can be called asynchronously and so should only be used by seasoned C#
/// experts. Ensure you use proper locks on thread-unsafe objects
/// </remarks>
public override void OnOrderEvent(OrderEvent orderEvent)
{
Log(orderEvent.ToString());
}
/// <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; } = false;
/// <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%"},
{"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", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$2.00"},
{"Fitness Score", "0"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "0"},
{"Return Over Maximum Drawdown", "0"},
{"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", "1130102123"}
};
}
}

View File

@@ -0,0 +1,111 @@
/*
* 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.Interfaces;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm testing the SetHolding trading API precision
/// </summary>
public class SetHoldingsRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
/// <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, 07);
SetEndDate(2013, 10, 08);
AddEquity("SPY", Resolution.Minute);
}
/// <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 (!Portfolio.Invested)
{
SetHoldings("SPY", 0.1m);
SetHoldings("SPY", 0.2d);
SetHoldings("SPY", 0.3f);
SetHoldings("SPY", 1);
}
}
/// <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", "4"},
{"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", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$5.41"},
{"Estimated Strategy Capacity", "$2800000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Fitness Score", "0.995"},
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "79228162514264337593543950335"},
{"Return Over Maximum Drawdown", "79228162514264337593543950335"},
{"Portfolio Turnover", "0.995"},
{"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", "211aa90fef127ec5652eff1b3d2b8ca8"}
};
}
}

View File

@@ -73,34 +73,34 @@ namespace QuantConnect.Algorithm.CSharp
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Trades", "7"},
{"Total Trades", "5"},
{"Average Win", "0%"},
{"Average Loss", "-0.35%"},
{"Compounding Annual Return", "239.778%"},
{"Drawdown", "2.300%"},
{"Average Loss", "-0.76%"},
{"Compounding Annual Return", "280.877%"},
{"Drawdown", "2.200%"},
{"Expectancy", "-1"},
{"Net Profit", "1.576%"},
{"Sharpe Ratio", "7.724"},
{"Probabilistic Sharpe Ratio", "65.265%"},
{"Net Profit", "1.724%"},
{"Sharpe Ratio", "9.01"},
{"Probabilistic Sharpe Ratio", "67.047%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.271"},
{"Beta", "1.028"},
{"Annual Standard Deviation", "0.229"},
{"Annual Variance", "0.052"},
{"Information Ratio", "-24.894"},
{"Tracking Error", "0.009"},
{"Treynor Ratio", "1.719"},
{"Total Fees", "$24.08"},
{"Estimated Strategy Capacity", "$18000000.00"},
{"Alpha", "0.026"},
{"Beta", "1.012"},
{"Annual Standard Deviation", "0.226"},
{"Annual Variance", "0.051"},
{"Information Ratio", "3.929"},
{"Tracking Error", "0.013"},
{"Treynor Ratio", "2.008"},
{"Total Fees", "$17.21"},
{"Estimated Strategy Capacity", "$29000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Fitness Score", "0.999"},
{"Kelly Criterion Estimate", "38.796"},
{"Kelly Criterion Probability Value", "0.228"},
{"Sortino Ratio", "79228162514264337593543950335"},
{"Return Over Maximum Drawdown", "68.799"},
{"Portfolio Turnover", "1.748"},
{"Return Over Maximum Drawdown", "91.3"},
{"Portfolio Turnover", "1.241"},
{"Total Insights Generated", "100"},
{"Total Insights Closed", "99"},
{"Total Insights Analysis Completed", "99"},
@@ -114,7 +114,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Mean Population Magnitude", "53.5354%"},
{"Rolling Averaged Population Direction", "58.2788%"},
{"Rolling Averaged Population Magnitude", "58.2788%"},
{"OrderListHash", "4e7e8421606feccde05e3fcd3aa6b459"}
{"OrderListHash", "1d1c126b61eb07c291b0e451864a7481"}
};
}
}

View File

@@ -42,16 +42,7 @@ namespace QuantConnect.Algorithm.CSharp
SetCash(100*1000);
// add universe for the top 50 stocks by dollar volume
AddUniverse(Universe.DollarVolume.Top(50));
// add universe for the bottom 50 stocks by dollar volume
AddUniverse(Universe.DollarVolume.Bottom(50));
// add universe for the 90th dollar volume percentile
AddUniverse(Universe.DollarVolume.Percentile(90));
// add universe for stocks between the 70th and 80th dollar volume percentile
AddUniverse(Universe.DollarVolume.Percentile(70, 80));
AddUniverse(Universe.Top(50));
}
public void OnData(TradeBars data)

View File

@@ -11,18 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *
from datetime import timedelta
from AlgorithmImports import *
from enum import Enum
class BasePairsTradingAlphaModel(AlphaModel):
@@ -182,4 +171,4 @@ class BasePairsTradingAlphaModel(AlphaModel):
# creates a group id and set the GroupId property on each insight object
return Insight.Group(longAsset1, shortAsset2)
return []
return []

View File

@@ -11,16 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import AlphaModel, Insight, InsightType, InsightDirection
from AlgorithmImports import *
class ConstantAlphaModel(AlphaModel):
''' Provides an implementation of IAlphaModel that always returns the same insight for each security'''
@@ -106,4 +97,4 @@ def strfdelta(tdelta):
d = tdelta.days
h, rem = divmod(tdelta.seconds, 3600)
m, s = divmod(rem, 60)
return "{}.{:02d}:{:02d}:{:02d}".format(d,h,m,s)
return "{}.{:02d}:{:02d}:{:02d}".format(d,h,m,s)

View File

@@ -11,18 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *
from AlgorithmImports import *
class EmaCrossAlphaModel(AlphaModel):
'''Alpha model that uses an EMA cross to create insights'''
@@ -102,4 +91,4 @@ class SymbolData:
@property
def SlowIsOverFast(self):
return not self.FastIsOverSlow
return not self.FastIsOverSlow

View File

@@ -11,15 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework.Alphas import *
from datetime import timedelta
from AlgorithmImports import *
class HistoricalReturnsAlphaModel(AlphaModel):
'''Uses Historical returns to create insights.'''

View File

@@ -11,18 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *
from AlgorithmImports import *
class MacdAlphaModel(AlphaModel):
'''Defines a custom alpha model that uses MACD crossovers. The MACD signal line

View File

@@ -11,19 +11,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework.Alphas import *
from AlgorithmImports import *
from Alphas.BasePairsTradingAlphaModel import BasePairsTradingAlphaModel
from datetime import timedelta
from scipy.stats import pearsonr
import numpy as np
import pandas as pd
class PearsonCorrelationPairsTradingAlphaModel(BasePairsTradingAlphaModel):
''' This alpha model is designed to rank every pair combination by its pearson correlation
@@ -114,4 +104,4 @@ class PearsonCorrelationPairsTradingAlphaModel(BasePairsTradingAlphaModel):
df = pd.DataFrame(series_dict).dropna()
return (df - df.shift(1)).dropna()
return (df - df.shift(1)).dropna()

View File

@@ -11,20 +11,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Logging")
AddReference("QuantConnect.Common")
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Logging import Log
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *
from datetime import timedelta
from AlgorithmImports import *
from QuantConnect.Logging import *
from enum import Enum
class RsiAlphaModel(AlphaModel):
@@ -137,4 +125,4 @@ class State(Enum):
'''Defines the state. This is used to prevent signal spamming and aid in bounce detection.'''
TrippedLow = 0
Middle = 1
TrippedHigh = 2
TrippedHigh = 2

View File

@@ -11,19 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from AlgorithmImports import *
class SpreadExecutionModel(ExecutionModel):
'''Execution model that submits orders while the current spread is tight.

View File

@@ -11,25 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Data import *
from QuantConnect.Data.Market import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Portfolio import *
import numpy as np
from AlgorithmImports import *
class StandardDeviationExecutionModel(ExecutionModel):
'''Execution model that submits orders while the current market prices is at least the configured number of standard

View File

@@ -11,26 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Data import *
from QuantConnect.Data.Market import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Portfolio import *
import numpy as np
from datetime import datetime
from AlgorithmImports import *
class VolumeWeightedAveragePriceExecutionModel(ExecutionModel):
'''Execution model that submits orders while the current market price is more favorable that the current volume weighted average price.'''
@@ -174,4 +155,4 @@ class IntradayVwap:
averagePrice = float(input.High + input.Low + input.Close) / 3
return True, float(input.Volume), averagePrice
return False, 0.0, 0.0
return False, 0.0, 0.0

View File

@@ -11,11 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect.Algorithm.Framework.Alphas import *
from AlgorithmImports import *
from Portfolio.EqualWeightingPortfolioConstructionModel import *
class AccumulativeInsightPortfolioConstructionModel(EqualWeightingPortfolioConstructionModel):

View File

@@ -11,26 +11,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Logging")
AddReference("QuantConnect.Indicators")
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Logging import Log
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from AlgorithmImports import *
from Portfolio.MaximumSharpeRatioPortfolioOptimizer import MaximumSharpeRatioPortfolioOptimizer
from datetime import datetime, timedelta
from itertools import groupby
import pandas as pd
import numpy as np
from numpy import dot, transpose
from numpy.linalg import inv

View File

@@ -11,12 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from AlgorithmImports import *
from InsightWeightingPortfolioConstructionModel import InsightWeightingPortfolioConstructionModel
class ConfidenceWeightedPortfolioConstructionModel(InsightWeightingPortfolioConstructionModel):

View File

@@ -15,6 +15,7 @@
using System;
using System.Linq;
using QuantConnect.Logging;
using QuantConnect.Securities;
using System.Collections.Generic;
using QuantConnect.Data.UniverseSelection;
@@ -89,7 +90,16 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
{
foreach (var portfolioTarget in _targetsPerSymbol.Values)
{
yield return portfolioTarget;
if (algorithm.Securities.ContainsKey(portfolioTarget.Symbol))
{
yield return portfolioTarget;
}
else
{
// this could happen if the algorithm has not yet added a security used by an alpha
Log.Error("EqualWeightingAlphaStreamsPortfolioConstructionModel.CreateTargets(): " +
$"Skip emitting portfolio target, security not found in algorithm {portfolioTarget.Symbol}");
}
}
}
}
@@ -123,7 +133,8 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
_rebalance = true;
_targetsPerSymbolPerAlpha[security.Symbol] = new Dictionary<Symbol, PortfolioTarget>();
var lastState = algorithm.History<AlphaStreamsPortfolioState>(security.Symbol, TimeSpan.FromDays(1)).LastOrDefault();
var lastState = security.Cache.GetData<AlphaStreamsPortfolioState>();
lastState ??= algorithm.GetLastKnownPrices(security).OfType<AlphaStreamsPortfolioState>().LastOrDefault();
if (lastState != null)
{
// keep the last state per alpha
@@ -213,6 +224,7 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
}
}
List<Symbol> symbolsToRemove = null;
// We adjust existing targets for symbols that got removed from this alpha
foreach (var removedTarget in ourExistingTargets.Values.Where(target => !newTargets.ContainsKey(target.Symbol)))
{
@@ -224,7 +236,8 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
newAggregatedTarget = new PortfolioTarget(symbol, quantity.DiscretelyRoundBy(_unitQuantity[symbol], MidpointRounding.ToZero));
}
ourExistingTargets.Remove(symbol);
symbolsToRemove ??= new List<Symbol>();
symbolsToRemove.Add(symbol);
if (existingAggregatedTarget == null || existingAggregatedTarget.Quantity != newAggregatedTarget.Quantity)
{
updatedTargets = true;
@@ -232,6 +245,15 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
}
}
if (symbolsToRemove != null)
{
for (var i = 0; i < symbolsToRemove.Count; i++)
{
// we can't remove from dictionary while iterating through it
ourExistingTargets.Remove(symbolsToRemove[i]);
}
}
return updatedTargets;
}
}

View File

@@ -11,15 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from itertools import groupby
from datetime import datetime, timedelta
from AlgorithmImports import *
class EqualWeightingPortfolioConstructionModel(PortfolioConstructionModel):
'''Provides an implementation of IPortfolioConstructionModel that gives equal weighting to all securities.

View File

@@ -11,12 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Algorithm.Framework.Alphas import *
from AlgorithmImports import *
from EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel, PortfolioBias
class InsightWeightingPortfolioConstructionModel(EqualWeightingPortfolioConstructionModel):

View File

@@ -11,8 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy as np
import pandas as pd
from AlgorithmImports import *
from scipy.optimize import minimize
### <summary>
@@ -94,4 +93,4 @@ class MaximumSharpeRatioPortfolioOptimizer:
def get_budget_constraint(self, weights):
'''Defines a budget constraint: the sum of the weights equals unity'''
return np.sum(weights) - 1
return np.sum(weights) - 1

View File

@@ -11,23 +11,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Indicators")
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from AlgorithmImports import *
from Portfolio.MinimumVariancePortfolioOptimizer import MinimumVariancePortfolioOptimizer
from datetime import timedelta
import numpy as np
import pandas as pd
### <summary>
### Provides an implementation of Mean-Variance portfolio optimization based on modern portfolio theory.

View File

@@ -11,8 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy as np
import pandas as pd
from AlgorithmImports import *
from scipy.optimize import minimize
### <summary>

View File

@@ -11,14 +11,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import Resolution
from QuantConnect.Algorithm.Framework.Alphas import *
from AlgorithmImports import *
from EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel
from itertools import groupby
class SectorWeightingPortfolioConstructionModel(EqualWeightingPortfolioConstructionModel):
'''Provides an implementation of IPortfolioConstructionModel that
@@ -105,4 +99,4 @@ class SectorWeightingPortfolioConstructionModel(EqualWeightingPortfolioConstruct
Other sectors can be defined using AssetClassification'''
fundamentals = security.Fundamentals
companyReference = security.Fundamentals.CompanyReference if fundamentals else None
return companyReference.IndustryTemplateCode if companyReference else None
return companyReference.IndustryTemplateCode if companyReference else None

View File

@@ -30,7 +30,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.5" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.6" />
<PackageReference Include="Accord" Version="3.6.0" />
<PackageReference Include="Accord.Math" Version="3.6.0" />
<PackageReference Include="Accord.Statistics" Version="3.6.0" />

View File

@@ -11,17 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from QuantConnect.Algorithm.Framework.Risk import *
from AlgorithmImports import *
class MaximumDrawdownPercentPerSecurity(RiskManagementModel):
'''Provides an implementation of IRiskManagementModel that limits the drawdown per holding to the specified percentage'''

View File

@@ -11,17 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from QuantConnect.Algorithm.Framework.Risk import *
from AlgorithmImports import *
class MaximumDrawdownPercentPortfolio(RiskManagementModel):
'''Provides an implementation of IRiskManagementModel that limits the drawdown of the portfolio to the specified percentage.'''

View File

@@ -11,16 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from QuantConnect.Algorithm.Framework.Risk import *
from AlgorithmImports import *
from itertools import groupby
class MaximumSectorExposureRiskManagementModel(RiskManagementModel):

View File

@@ -11,17 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from QuantConnect.Algorithm.Framework.Risk import *
from AlgorithmImports import *
class MaximumUnrealizedProfitPercentPerSecurity(RiskManagementModel):
'''Provides an implementation of IRiskManagementModel that limits the unrealized profit per holding to the specified percentage'''

View File

@@ -27,7 +27,7 @@ namespace QuantConnect.Algorithm.Framework.Risk
public class TrailingStopRiskManagementModel : RiskManagementModel
{
private readonly decimal _maximumDrawdownPercent;
private Dictionary<Symbol, decimal> _trailingHighs = new Dictionary<Symbol, decimal>();
private readonly Dictionary<Symbol, decimal> _trailing = new Dictionary<Symbol, decimal>();
/// <summary>
/// Initializes a new instance of the <see cref="TrailingStopRiskManagementModel"/> class
@@ -35,7 +35,7 @@ namespace QuantConnect.Algorithm.Framework.Risk
/// <param name="maximumDrawdownPercent">The maximum percentage relative drawdown allowed for algorithm portfolio compared with the highest unrealized profit, defaults to 5% drawdown per security</param>
public TrailingStopRiskManagementModel(decimal maximumDrawdownPercent = 0.05m)
{
_maximumDrawdownPercent = -Math.Abs(maximumDrawdownPercent);
_maximumDrawdownPercent = Math.Abs(maximumDrawdownPercent);
}
/// <summary>
@@ -53,32 +53,32 @@ namespace QuantConnect.Algorithm.Framework.Risk
// Remove if not invested
if (!security.Invested)
{
if (_trailingHighs.ContainsKey(symbol))
if (_trailing.ContainsKey(symbol))
{
_trailingHighs.Remove(symbol);
_trailing.Remove(symbol);
}
continue;
}
// Add newly invested securities
if (!_trailingHighs.ContainsKey(symbol))
var profitPercent = security.Holdings.UnrealizedProfitPercent;
decimal value;
if (!_trailing.TryGetValue(symbol, out value))
{
_trailingHighs.Add(symbol, security.Holdings.AveragePrice); // Set to average holding cost
var newValue = profitPercent > 0 ? profitPercent : 0;
_trailing.Add(symbol, newValue);
continue;
}
// Check for new highs and update - set to tradebar high
if (_trailingHighs[symbol] < security.High)
// Check for new high and update
if (value < profitPercent)
{
_trailingHighs[symbol] = security.High;
_trailing[symbol] = profitPercent;
continue;
}
// Check for securities past the drawdown limit
var securityHigh = _trailingHighs[symbol];
var drawdown = (security.Low / securityHigh) - 1m;
if (drawdown < _maximumDrawdownPercent)
// If unrealized profit percent deviates from local max for more than affordable percentage
if (profitPercent < value - _maximumDrawdownPercent)
{
// liquidate
yield return new PortfolioTarget(security.Symbol, 0);
@@ -86,4 +86,4 @@ namespace QuantConnect.Algorithm.Framework.Risk
}
}
}
}
}

View File

@@ -11,17 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from QuantConnect.Algorithm.Framework.Risk import *
from AlgorithmImports import *
class TrailingStopRiskManagementModel(RiskManagementModel):
'''Provides an implementation of IRiskManagementModel that limits the maximum possible loss
@@ -30,8 +20,8 @@ class TrailingStopRiskManagementModel(RiskManagementModel):
'''Initializes a new instance of the TrailingStopRiskManagementModel class
Args:
maximumDrawdownPercent: The maximum percentage drawdown allowed for algorithm portfolio compared with the highest unrealized profit, defaults to 5% drawdown'''
self.maximumDrawdownPercent = -abs(maximumDrawdownPercent)
self.trailingHighs = dict()
self.maximumDrawdownPercent = abs(maximumDrawdownPercent)
self.trailing = dict()
def ManageRisk(self, algorithm, targets):
'''Manages the algorithm's risk at each time step
@@ -46,24 +36,25 @@ class TrailingStopRiskManagementModel(RiskManagementModel):
# Remove if not invested
if not security.Invested:
self.trailingHighs.pop(symbol, None)
self.trailing.pop(symbol, None)
continue
profitPercent = security.Holdings.UnrealizedProfitPercent
# Add newly invested securities
if symbol not in self.trailingHighs:
self.trailingHighs[symbol] = security.Holdings.AveragePrice # Set to average holding cost
value = self.trailing.get(symbol)
if value == None:
newValue = profitPercent if profitPercent > 0 else 0
self.trailing[symbol] = newValue
continue
# Check for new highs and update - set to tradebar high
if self.trailingHighs[symbol] < security.High:
self.trailingHighs[symbol] = security.High
# Check for new high and update
if value < profitPercent:
self.trailing[symbol] = profitPercent
continue
# Check for securities past the drawdown limit
securityHigh = self.trailingHighs[symbol]
drawdown = (security.Low / securityHigh) - 1
if drawdown < self.maximumDrawdownPercent:
# If unrealized profit percent deviates from local max for more than affordable percentage
if profitPercent < value - self.maximumDrawdownPercent:
# liquidate
riskAdjustedTargets.append(PortfolioTarget(symbol, 0))

View File

@@ -11,14 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Indicators import *
from AlgorithmImports import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
class EmaCrossUniverseSelectionModel(FundamentalUniverseSelectionModel):

View File

@@ -67,7 +67,7 @@ namespace QuantConnect.Algorithm.Framework.Selection
/// <summary>
/// Creates the coarse fundamental universe object.
/// This is provided to allow more flexibility when creating coarse universe, such as using algorithm.Universe.DollarVolume.Top(5)
/// This is provided to allow more flexibility when creating coarse universe.
/// </summary>
/// <param name="algorithm">The algorithm instance</param>
/// <returns>The coarse fundamental universe</returns>

View File

@@ -11,12 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect.Data.UniverseSelection import *
from AlgorithmImports import *
class FundamentalUniverseSelectionModel:
'''Provides a base class for defining equity coarse/fine fundamental selection models'''
@@ -46,7 +41,7 @@ class FundamentalUniverseSelectionModel:
def CreateCoarseFundamentalUniverse(self, algorithm):
'''Creates the coarse fundamental universe object.
This is provided to allow more flexibility when creating coarse universe, such as using algorithm.Universe.DollarVolume.Top(5)
This is provided to allow more flexibility when creating coarse universe.
Args:
algorithm: The algorithm instance
Returns:
@@ -85,4 +80,4 @@ class FundamentalUniverseSelectionModel:
fine: The fine fundamental data used to perform filtering
Returns:
An enumerable of symbols passing the filter'''
return [f.Symbol for f in fine]
return [f.Symbol for f in fine]

View File

@@ -11,18 +11,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
from AlgorithmImports import *
from clr import GetClrType as typeof
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Securities import *
from QuantConnect.Data.Auxiliary import *
from QuantConnect.Data.UniverseSelection import *
from Selection.UniverseSelectionModel import UniverseSelectionModel
from datetime import datetime
class FutureUniverseSelectionModel(UniverseSelectionModel):
'''Provides an implementation of IUniverseSelectionMode that subscribes to future chains'''

View File

@@ -11,18 +11,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
from AlgorithmImports import *
from clr import GetClrType as typeof
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Securities import *
from QuantConnect.Data.Auxiliary import *
from QuantConnect.Data.UniverseSelection import *
from Selection.UniverseSelectionModel import UniverseSelectionModel
from datetime import datetime
class OptionUniverseSelectionModel(UniverseSelectionModel):
'''Provides an implementation of IUniverseSelectionMode that subscribes to option chains'''

View File

@@ -11,12 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect.Data.UniverseSelection import *
from AlgorithmImports import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
from itertools import groupby
from math import ceil
@@ -87,4 +82,4 @@ class QC500UniverseSelectionModel(FundamentalUniverseSelectionModel):
sortedByDollarVolume.extend(y[:c])
sortedByDollarVolume = sorted(sortedByDollarVolume, key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse=True)
return [x.Symbol for x in sortedByDollarVolume[:self.numberOfSymbolsFine]]
return [x.Symbol for x in sortedByDollarVolume[:self.numberOfSymbolsFine]]

View File

@@ -11,17 +11,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Common")
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework import *
from AlgorithmImports import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
import pandas as pd
class UncorrelatedUniverseSelectionModel(FundamentalUniverseSelectionModel):
'''This universe selection model picks stocks that currently have their correlation to a benchmark deviated from the mean.'''

View File

@@ -0,0 +1,57 @@
# 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 template algorithm for the Atreyu brokerage
### </summary>
### <meta name="tag" content="using data" />
### <meta name="tag" content="using quantconnect" />
### <meta name="tag" content="trading and orders" />
class BasicTemplateAtreyuAlgorithm(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,10, 7) #Set Start Date
self.SetEndDate(2013,10,11) #Set End Date
self.SetCash(100000) #Set Strategy Cash
self.SetBrokerageModel(BrokerageName.Atreyu)
self.AddEquity("SPY", Resolution.Minute)
self.DefaultOrderProperties = AtreyuOrderProperties()
# Can specify the default exchange to execute an order on.
# If not specified will default to the primary exchange
self.DefaultOrderProperties.Exchange = Exchange.NASDAQ
# Currently only support order for the day
self.DefaultOrderProperties.TimeInForce = TimeInForce.Day
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
'''
if not self.Portfolio.Invested:
# will set 25% of our buying power with a market order that will be routed to exchange set in the default order properties (NASDAQ)
self.SetHoldings("SPY", 0.25)
# will increase our SPY holdings to 50% of our buying power with a market order that will be routed to ARCA
orderProperties = AtreyuOrderProperties()
orderProperties.Exchange = Exchange.ARCA
self.SetHoldings("SPY", 0.50, orderProperties = orderProperties)
self.Debug("Purchased SPY!")

View File

@@ -33,4 +33,4 @@ class ConstituentsQC500GeneratorAlgorithm(QCAlgorithm):
self.SetCash(100000) # Set Strategy Cash
# Add QC500 Universe
self.AddUniverse(self.Universe.Index.QC500)
self.AddUniverse(self.Universe.QC500)

View File

@@ -33,7 +33,7 @@ class ETFConstituentUniverseCompositeDelistingRegressionAlgorithm(QCAlgorithm):
self.aapl = self.AddEquity("AAPL", Resolution.Hour).Symbol
self.gdvd = self.AddEquity("GDVD", Resolution.Hour).Symbol
self.AddUniverse(ETFConstituentsUniverse(self.gdvd, self.UniverseSettings, self.FilterETFs))
self.AddUniverse(self.Universe.ETF(self.gdvd, self.UniverseSettings, self.FilterETFs))
def FilterETFs(self, constituents):
if self.UtcTime.date() > self.delistingDate:

View File

@@ -33,7 +33,7 @@ class ETFConstituentUniverseCompositeDelistingRegressionAlgorithmNoAddEquityETF(
self.aapl = self.AddEquity("AAPL", Resolution.Hour).Symbol
self.gdvd = Symbol.Create("GDVD", SecurityType.Equity, Market.USA)
self.AddUniverse(ETFConstituentsUniverse(self.gdvd, self.UniverseSettings, self.FilterETFs))
self.AddUniverse(self.Universe.ETF(self.gdvd, self.UniverseSettings, self.FilterETFs))
def FilterETFs(self, constituents):
if self.UtcTime.date() > self.delistingDate:

View File

@@ -35,7 +35,7 @@ class ETFConstituentUniverseFilterFunctionRegressionAlgorithm(QCAlgorithm):
self.spy = self.AddEquity("SPY", Resolution.Hour).Symbol
self.aapl = Symbol.Create("AAPL", SecurityType.Equity, Market.USA)
self.AddUniverse(ETFConstituentsUniverse(self.spy, self.UniverseSettings, self.FilterETFs))
self.AddUniverse(self.Universe.ETF(self.spy, self.UniverseSettings, self.FilterETFs))
def FilterETFs(self, constituents):
constituentsData = list(constituents)
@@ -108,4 +108,4 @@ class ETFConstituentUniverseFilterFunctionRegressionAlgorithm(QCAlgorithm):
raise Exception("Security changes never propagated to the algorithm")
if not self.receivedData:
raise Exception("Data was never loaded for the S&P 500 constituent AAPL")
raise Exception("Data was never loaded for the S&P 500 constituent AAPL")

View File

@@ -0,0 +1,145 @@
# 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.
import typing
from AlgorithmImports import *
constituentData = []
### <summary>
### Alpha model for ETF constituents, where we generate insights based on the weighting
### of the ETF constituent
### </summary>
class ETFConstituentAlphaModel(AlphaModel):
def OnSecuritiesChanged(self, algorithm, changes):
pass
### <summary>
### Creates new insights based on constituent data and their weighting
### in their respective ETF
### </summary>
def Update(self, algorithm: QCAlgorithm, data: Slice):
insights = []
for constituent in constituentData:
if constituent.Symbol not in data.Bars and \
constituent.Symbol not in data.QuoteBars:
continue
insightDirection = InsightDirection.Up if constituent.Weight is not None and constituent.Weight >= 0.01 else InsightDirection.Down
insights.append(Insight(
algorithm.UtcTime,
constituent.Symbol,
timedelta(days=1),
InsightType.Price,
insightDirection,
float(1 * int(insightDirection)),
1.0,
weight=float(0 if constituent.Weight is None else constituent.Weight)
))
return insights
### <summary>
### Generates targets for ETF constituents, which will be set to the weighting
### of the constituent in their respective ETF
### </summary>
class ETFConstituentPortfolioModel(PortfolioConstructionModel):
def __init__(self):
self.hasAdded = False
### <summary>
### Securities changed, detects if we've got new additions to the universe
### so that we don't try to trade every loop
### </summary>
def OnSecuritiesChanged(self, algorithm: QCAlgorithm, changes: SecurityChanges):
self.hasAdded = len(changes.AddedSecurities) != 0
### <summary>
### Creates portfolio targets based on the insights provided to us by the alpha model.
### Emits portfolio targets setting the quantity to the weight of the constituent
### in its respective ETF.
### </summary>
def CreateTargets(self, algorithm: QCAlgorithm, insights: typing.List[Insight]):
if not self.hasAdded:
return []
finalInsights = []
for insight in insights:
finalInsights.append(PortfolioTarget(insight.Symbol, float(0 if insight.Weight is None else insight.Weight)))
self.hasAdded = False
return finalInsights
### <summary>
### Executes based on ETF constituent weighting
### </summary>
class ETFConstituentExecutionModel(ExecutionModel):
### <summary>
### Liquidates if constituents have been removed from the universe
### </summary>
def OnSecuritiesChanged(self, algorithm: QCAlgorithm, changes: SecurityChanges):
for change in changes.RemovedSecurities:
algorithm.Liquidate(change.Symbol)
### <summary>
### Creates orders for constituents that attempts to add
### the weighting of the constituent in our portfolio. The
### resulting algorithm portfolio weight might not be equal
### to the leverage of the ETF (1x, 2x, 3x, etc.)
### </summary>
def Execute(self, algorithm: QCAlgorithm, targets: typing.List[IPortfolioTarget]):
for target in targets:
algorithm.SetHoldings(target.Symbol, target.Quantity)
### <summary>
### Tests ETF constituents universe selection with the algorithm framework models (Alpha, PortfolioConstruction, Execution)
### </summary>
class ETFConstituentUniverseFrameworkRegressionAlgorithm(QCAlgorithm):
### <summary>
### Initializes the algorithm, setting up the framework classes and ETF constituent universe settings
### </summary>
def Initialize(self):
self.SetStartDate(2020, 12, 1)
self.SetEndDate(2021, 1, 31)
self.SetCash(100000)
self.SetAlpha(ETFConstituentAlphaModel())
self.SetPortfolioConstruction(ETFConstituentPortfolioModel())
self.SetExecution(ETFConstituentExecutionModel())
spy = Symbol.Create("SPY", SecurityType.Equity, Market.USA)
self.UniverseSettings.Resolution = Resolution.Hour
self.AddUniverse(self.Universe.ETF(spy, self.UniverseSettings, self.FilterETFConstituents))
### <summary>
### Filters ETF constituents
### </summary>
### <param name="constituents">ETF constituents</param>
### <returns>ETF constituent Symbols that we want to include in the algorithm</returns>
def FilterETFConstituents(self, constituents):
global constituentData
constituentDataLocal = [i for i in constituents if i is not None and i.Weight >= 0.001]
constituentData = list(constituentDataLocal)
return [i.Symbol for i in constituentDataLocal]
### <summary>
### no-op for performance
### </summary>
def OnData(self, data):
pass

View File

@@ -33,7 +33,7 @@ class ETFConstituentUniverseFilterFunctionRegressionAlgorithm(QCAlgorithm):
self.aapl = Symbol.Create("AAPL", SecurityType.Equity, Market.USA)
self.qqq = self.AddEquity("QQQ", Resolution.Daily).Symbol
self.AddUniverse(ETFConstituentsUniverse(self.qqq, self.UniverseSettings, self.FilterETFs))
self.AddUniverse(self.Universe.ETF(self.qqq, self.UniverseSettings, self.FilterETFs))
def FilterETFs(self, constituents):
constituentSymbols = [i.Symbol for i in constituents]
@@ -85,4 +85,4 @@ class ETFConstituentUniverseFilterFunctionRegressionAlgorithm(QCAlgorithm):
for constituentDate, constituentEncountered in self.constituentDataEncountered.items():
if not constituentEncountered:
raise Exception(f"Received data in OnData(...) but it did not contain any constituent data on {constituentDate.strftime('%Y-%m-%d %H:%M:%S.%f')}")
raise Exception(f"Received data in OnData(...) but it did not contain any constituent data on {constituentDate.strftime('%Y-%m-%d %H:%M:%S.%f')}")

View File

@@ -0,0 +1,123 @@
# 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.
import typing
from AlgorithmImports import *
from datetime import timedelta
### <summary>
### Example algorithm demonstrating the usage of the RSI indicator
### in combination with ETF constituents data to replicate the weighting
### of the ETF's assets in our own account.
### </summary>
class ETFConstituentUniverseRSIAlphaModelAlgorithm(QCAlgorithm):
### <summary>
### Initialize the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
### </summary>
def Initialize(self):
self.SetStartDate(2020, 12, 1)
self.SetEndDate(2021, 1, 31)
self.SetCash(100000)
self.SetAlpha(ConstituentWeightedRsiAlphaModel())
self.SetPortfolioConstruction(InsightWeightingPortfolioConstructionModel())
self.SetExecution(ImmediateExecutionModel())
spy = self.AddEquity("SPY", Resolution.Hour).Symbol
# We load hourly data for ETF constituents in this algorithm
self.UniverseSettings.Resolution = Resolution.Hour
self.Settings.MinimumOrderMarginPortfolioPercentage = 0.01
self.AddUniverse(self.Universe.ETF(spy, self.UniverseSettings, self.FilterETFConstituents))
### <summary>
### Filters ETF constituents
### </summary>
### <param name="constituents">ETF constituents</param>
### <returns>ETF constituent Symbols that we want to include in the algorithm</returns>
def FilterETFConstituents(self, constituents):
return [i.Symbol for i in constituents if i.Weight is not None and i.Weight >= 0.001]
### <summary>
### Alpha model making use of the RSI indicator and ETF constituent weighting to determine
### which assets we should invest in and the direction of investment
### </summary>
class ConstituentWeightedRsiAlphaModel(AlphaModel):
def __init__(self, maxTrades=None):
self.rsiSymbolData = {}
def Update(self, algorithm: QCAlgorithm, data: Slice):
algoConstituents = []
for barSymbol in data.Bars.Keys:
if not algorithm.Securities[barSymbol].Cache.HasData(ETFConstituentData):
continue
constituentData = algorithm.Securities[barSymbol].Cache.GetData[ETFConstituentData]()
algoConstituents.append(constituentData)
if len(algoConstituents) == 0 or len(data.Bars) == 0:
# Don't do anything if we have no data we can work with
return []
constituents = {i.Symbol:i for i in algoConstituents}
for bar in data.Bars.Values:
if bar.Symbol not in constituents:
# Dealing with a manually added equity, which in this case is SPY
continue
if bar.Symbol not in self.rsiSymbolData:
# First time we're initializing the RSI.
# It won't be ready now, but it will be
# after 7 data points
constituent = constituents[bar.Symbol]
self.rsiSymbolData[bar.Symbol] = SymbolData(bar.Symbol, algorithm, constituent, 7)
allReady = all([sd.rsi.IsReady for sd in self.rsiSymbolData.values()])
if not allReady:
# We're still warming up the RSI indicators.
return []
insights = []
for symbol, symbolData in self.rsiSymbolData.items():
averageLoss = symbolData.rsi.AverageLoss.Current.Value
averageGain = symbolData.rsi.AverageGain.Current.Value
# If we've lost more than gained, then we think it's going to go down more
direction = InsightDirection.Down if averageLoss > averageGain else InsightDirection.Up
# Set the weight of the insight as the weight of the ETF's
# holding. The InsightWeightingPortfolioConstructionModel
# will rebalance our portfolio to have the same percentage
# of holdings in our algorithm that the ETF has.
insights.append(Insight.Price(
symbol,
timedelta(days=1),
direction,
float(averageLoss if direction == InsightDirection.Down else averageGain),
weight=float(symbolData.constituent.Weight)
))
return insights
class SymbolData:
def __init__(self, symbol, algorithm, constituent, period):
self.Symbol = symbol
self.constituent = constituent
self.rsi = algorithm.RSI(symbol, period, MovingAverageType.Exponential, Resolution.Hour)

View File

@@ -37,7 +37,7 @@
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.5" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.6" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -77,7 +77,6 @@
<None Include="TrainingExampleAlgorithm.py" />
<None Include="LongOnlyAlphaStreamAlgorithm.py" />
<None Include="CustomPartialFillModelAlgorithm.py" />
<Content Include="BasicTemplateConstituentUniverseAlgorithm.py" />
<Content Include="BasicTemplateOptionsConsolidationAlgorithm.py" />
<None Include="BasicTemplateOptionsPriceModel.py" />
<Content Include="CoarseFineOptionUniverseChainRegressionAlgorithm.py" />
@@ -140,6 +139,8 @@
<None Include="TensorFlowNeuralNetworkAlgorithm.py" />
<None Include="TiingoPriceAlgorithm.py" />
<None Include="PearsonCorrelationPairsTradingAlphaModelFrameworkAlgorithm.py" />
<None Include="UniverseSelectionDefinitionsAlgorithm.py" />
<None Include="ConstituentsQC500GeneratorAlgorithm.py" />
</ItemGroup>
<ItemGroup>
<None Include="AddRemoveSecurityRegressionAlgorithm.py" />
@@ -171,7 +172,6 @@
<None Include="CoarseFineFundamentalRegressionAlgorithm.py" />
<None Include="CoarseFundamentalTop3Algorithm.py" />
<None Include="CompositeAlphaModelFrameworkAlgorithm.py" />
<None Include="ConstituentsQC500GeneratorAlgorithm.py" />
<None Include="CustomBenchmarkAlgorithm.py" />
<None Include="CustomChartingAlgorithm.py" />
<None Include="CustomDataBitcoinAlgorithm.py" />
@@ -238,7 +238,6 @@
<None Include="TimeInForceAlgorithm.py" />
<None Include="TrailingStopRiskFrameworkAlgorithm.py" />
<None Include="UncorrelatedUniverseSelectionFrameworkAlgorithm.py" />
<None Include="UniverseSelectionDefinitionsAlgorithm.py" />
<None Include="UniverseSelectionRegressionAlgorithm.py" />
<None Include="UpdateOrderRegressionAlgorithm.py" />
<None Include="UserDefinedUniverseAlgorithm.py" />

View File

@@ -43,7 +43,6 @@
<Compile Include="CompositeRiskManagementModelFrameworkAlgorithm.py" />
<Compile Include="ConfidenceWeightedFrameworkAlgorithm.py" />
<Compile Include="ConsolidateRegressionAlgorithm.py" />
<Compile Include="ConstituentsQC500GeneratorAlgorithm.py" />
<Compile Include="ConstituentsUniverseRegressionAlgorithm.py" />
<Compile Include="ConvertToFrameworkAlgorithm.py" />
<Compile Include="CustomBuyingPowerModelAlgorithm.py" />

View File

@@ -14,27 +14,26 @@
from AlgorithmImports import *
### <summary>
### Basic template algorithm which showcases ConstituentsUniverse simple use case
### Regression algorithm testing the SetHolding trading API precision
### </summary>
class BasicTemplateConstituentUniverseAlgorithm(QCAlgorithm):
class SetHoldingsRegressionAlgorithm(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,10, 7)
self.SetEndDate(2013,10,11)
# by default will use algorithms UniverseSettings
self.AddUniverse(self.Universe.Constituent.Steel())
self.SetStartDate(2013, 10, 7)
self.SetEndDate(2013, 10, 8)
self.AddEquity("SPY", Resolution.Minute)
# we specify the UniverseSettings it should use
self.AddUniverse(self.Universe.Constituent.AggressiveGrowth(
UniverseSettings(Resolution.Hour,
2,
False,
False,
self.UniverseSettings.MinimumTimeInUniverse)))
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
self.SetAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromDays(1)))
self.SetExecution(ImmediateExecutionModel())
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
Arguments:
data: Slice object keyed by symbol containing the stock data
'''
if not self.Portfolio.Invested:
self.SetHoldings("SPY", 0.1)
self.SetHoldings("SPY", np.float(0.20))
self.SetHoldings("SPY", np.float64(0.30))
self.SetHoldings("SPY", 1)

View File

@@ -32,16 +32,7 @@ class UniverseSelectionDefinitionsAlgorithm(QCAlgorithm):
self.SetCash(100000) # Set Strategy Cash
# add universe for the top 50 stocks by dollar volume
self.AddUniverse(self.Universe.DollarVolume.Top(50))
# add universe for the bottom 50 stocks by dollar volume
self.AddUniverse(self.Universe.DollarVolume.Bottom(50))
# add universe for the 90th dollar volume percentile
self.AddUniverse(self.Universe.DollarVolume.Percentile(90.0))
# add universe for stocks between the 70th and 80th dollar volume percentile
self.AddUniverse(self.Universe.DollarVolume.Percentile(70.0, 80.0))
self.AddUniverse(self.Universe.Top(50))
self.changes = None

View File

@@ -11,11 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Algorithm")
from QuantConnect.Algorithm.Framework.Alphas import AlphaModel
from AlgorithmImports import *
class NullAlphaModel(AlphaModel):
'''Provides a null implementation of an alpha model'''
@@ -27,4 +23,4 @@ class NullAlphaModel(AlphaModel):
data: The new data available
Returns:
The new insights generated'''
return []
return []

View File

@@ -14,6 +14,7 @@
*
*/
using System;
using System.Collections.Generic;
using System.Linq;
using MathNet.Numerics.Statistics;
@@ -46,94 +47,10 @@ namespace QuantConnect.Algorithm
/// <param name="universeSettings">The settings for stocks added by this universe.
/// Defaults to <see cref="QCAlgorithm.UniverseSettings"/></param>
/// <returns>A new coarse universe for the top count of stocks by dollar volume</returns>
[Obsolete("This method is deprecated. Use method `Universe.DollarVolume.Top(...)` instead")]
public Universe Top(int count, UniverseSettings universeSettings = null)
{
universeSettings = universeSettings ?? _algorithm.UniverseSettings;
var symbol = Symbol.Create("us-equity-dollar-volume-top-" + count, SecurityType.Equity, Market.USA);
var config = new SubscriptionDataConfig(typeof(CoarseFundamental), symbol, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, false, false, true);
return new FuncUniverse(config, universeSettings, selectionData => (
from c in selectionData.OfType<CoarseFundamental>()
orderby c.DollarVolume descending
select c.Symbol).Take(count)
);
}
/// <summary>
/// Creates a new coarse universe that contains the bottom count of stocks
/// by daily dollar volume
/// </summary>
/// <param name="count">The number of stock to select</param>
/// <param name="universeSettings">The settings for stocks added by this universe.
/// Defaults to <see cref="QCAlgorithm.UniverseSettings"/></param>
/// <returns>A new coarse universe for the bottom count of stocks by dollar volume</returns>
public Universe Bottom(int count, UniverseSettings universeSettings = null)
{
universeSettings = universeSettings ?? _algorithm.UniverseSettings;
var symbol = Symbol.Create("us-equity-dollar-volume-bottom-" + count, SecurityType.Equity, Market.USA);
var config = new SubscriptionDataConfig(typeof(CoarseFundamental), symbol, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, false, false, true);
return new FuncUniverse(config, universeSettings, selectionData => (
from c in selectionData.OfType<CoarseFundamental>()
orderby c.DollarVolume descending
select c.Symbol).Take(count)
);
}
/// <summary>
/// Creates a new coarse universe that contains stocks in the specified
/// dollar volume percentile
/// </summary>
/// <param name="percentile">The desired dollar volume percentile (0 to 100 inclusive)</param>
/// <param name="universeSettings">The settings for stocks added by this universe.
/// Defaults to <see cref="QCAlgorithm.UniverseSettings"/></param>
/// <returns>A new coarse universe for the bottom count of stocks by dollar volume</returns>
public Universe Percentile(double percentile, UniverseSettings universeSettings = null)
{
universeSettings = universeSettings ?? _algorithm.UniverseSettings;
var symbol = Symbol.Create("us-equity-dollar-volume-percentile-" + percentile, SecurityType.Equity, Market.USA);
var config = new SubscriptionDataConfig(typeof(CoarseFundamental), symbol, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, false, false, true);
return new FuncUniverse(config, universeSettings, selectionData =>
{
var list = selectionData as IReadOnlyList<CoarseFundamental> ?? selectionData.OfType<CoarseFundamental>().ToList();
// using quantiles since the Percentile implementation requires integers, so scale into quantile space
var lowerBound = (decimal)list.Select(x => (double)x.DollarVolume).Quantile(percentile / 100d);
return from c in list
where c.DollarVolume >= lowerBound
orderby c.DollarVolume descending
select c.Symbol;
});
}
/// <summary>
/// Creates a new coarse universe that contains stocks in the specified dollar volume percentile range,
/// that is, this universe will produce stocks with dollar volumes between the lower percentile bound
/// and the upper percentile bound
/// </summary>
/// <param name="lowerPercentile">The desired lower dollar volume percentile bound (0 to 100 inclusive)</param>
/// <param name="upperPercentile">The desired upper dollar volume percentile bound (0 to 100 inclusive)</param>
/// <param name="universeSettings">The settings for stocks added by this universe.
/// Defaults to <see cref="QCAlgorithm.UniverseSettings"/></param>
/// <returns>A new coarse universe for the bottom count of stocks by dollar volume</returns>
public Universe Percentile(double lowerPercentile, double upperPercentile, UniverseSettings universeSettings = null)
{
universeSettings = universeSettings ?? _algorithm.UniverseSettings;
var symbol = Symbol.Create("us-equity-dollar-volume-percentile-" + lowerPercentile + "-" + upperPercentile, SecurityType.Equity, Market.USA);
var config = new SubscriptionDataConfig(typeof(CoarseFundamental), symbol, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, false, false, true);
return new FuncUniverse(config, universeSettings, selectionData =>
{
var list = selectionData as IReadOnlyList<CoarseFundamental> ?? selectionData.OfType<CoarseFundamental>().ToList();
// using quantiles since the Percentile implementation requires integers, so scale into quantile space
var lowerBound = (decimal) list.Select(x => (double) x.DollarVolume).Quantile(lowerPercentile/100d);
var upperBound = (decimal) list.Select(x => (double) x.DollarVolume).Quantile(upperPercentile/100d);
return from c in list
where c.DollarVolume >= lowerBound
where c.DollarVolume <= upperBound
orderby c.DollarVolume descending
select c.Symbol;
});
return _algorithm.Universe.Top(count, universeSettings);
}
}
}
}

View File

@@ -13,9 +13,10 @@
* limitations under the License.
*/
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Orders;
using QuantConnect.Securities;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Algorithm.Framework.Portfolio;
namespace QuantConnect.Algorithm.Framework.Execution
{
@@ -40,11 +41,17 @@ namespace QuantConnect.Algorithm.Framework.Execution
{
foreach (var target in _targetsCollection.OrderByMarginImpact(algorithm))
{
var security = algorithm.Securities[target.Symbol];
// calculate remaining quantity to be ordered
var quantity = OrderSizing.GetUnorderedQuantity(algorithm, target);
var quantity = OrderSizing.GetUnorderedQuantity(algorithm, target, security);
if (quantity != 0)
{
algorithm.MarketOrder(target.Symbol, quantity);
if (security.BuyingPowerModel.AboveMinimumOrderMarginPortfolioPercentage(security, quantity,
algorithm.Portfolio, algorithm.Settings.MinimumOrderMarginPortfolioPercentage))
{
algorithm.MarketOrder(security, quantity);
}
}
}
@@ -61,4 +68,4 @@ namespace QuantConnect.Algorithm.Framework.Execution
{
}
}
}
}

View File

@@ -11,19 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from AlgorithmImports import *
class ImmediateExecutionModel(ExecutionModel):
'''Provides an implementation of IExecutionModel that immediately submits market orders to achieve the desired portfolio targets'''
@@ -42,9 +30,12 @@ class ImmediateExecutionModel(ExecutionModel):
self.targetsCollection.AddRange(targets)
if self.targetsCollection.Count > 0:
for target in self.targetsCollection.OrderByMarginImpact(algorithm):
security = algorithm.Securities[target.Symbol]
# calculate remaining quantity to be ordered
quantity = OrderSizing.GetUnorderedQuantity(algorithm, target)
quantity = OrderSizing.GetUnorderedQuantity(algorithm, target, security)
if quantity != 0:
algorithm.MarketOrder(target.Symbol, quantity)
aboveMinimumPortfolio = BuyingPowerModelExtensions.AboveMinimumOrderMarginPortfolioPercentage(security.BuyingPowerModel, security, quantity, algorithm.Portfolio, algorithm.Settings.MinimumOrderMarginPortfolioPercentage)
if aboveMinimumPortfolio:
algorithm.MarketOrder(security, quantity)
self.targetsCollection.ClearFulfilled(algorithm)

View File

@@ -11,9 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Algorithm")
from QuantConnect.Algorithm.Framework.Execution import *
from AlgorithmImports import *
class NullExecutionModel(ExecutionModel):
'''Provides an implementation of IExecutionModel that does nothing'''

View File

@@ -1,141 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using QuantConnect.Data.UniverseSelection;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm
{
/// <summary>
/// Provides helpers for defining universes based on index definitions
/// </summary>
public class IndexUniverseDefinitions
{
private readonly QCAlgorithm _algorithm;
/// <summary>
/// Initializes a new instance of the <see cref="IndexUniverseDefinitions"/> class
/// </summary>
/// <param name="algorithm">The algorithm instance, used for obtaining the default <see cref="UniverseSettings"/></param>
public IndexUniverseDefinitions(QCAlgorithm algorithm)
{
_algorithm = algorithm;
}
/// <summary>
/// Creates a new fine universe that contains the constituents of QC500 index based onthe company fundamentals
/// The algorithm creates a default tradable and liquid universe containing 500 US equities
/// which are chosen at the first trading day of each month.
/// </summary>
/// <returns>A new coarse universe for the top count of stocks by dollar volume</returns>
public Universe QC500
{
get
{
var lastMonth = -1;
var numberOfSymbolsCoarse = 1000;
var numberOfSymbolsFine = 500;
var dollarVolumeBySymbol = new Dictionary<Symbol, decimal>();
var symbol = Symbol.Create("qc-500", SecurityType.Equity, Market.USA);
var coarseUniverse = new CoarseFundamentalUniverse(
symbol,
_algorithm.UniverseSettings,
coarse =>
{
if (_algorithm.Time.Month == lastMonth)
{
return Universe.Unchanged;
}
// The stocks must have fundamental data
// The stock must have positive previous-day close price
// The stock must have positive volume on the previous trading day
var sortedByDollarVolume =
(from x in coarse
where x.HasFundamentalData && x.Volume > 0 && x.Price > 0
orderby x.DollarVolume descending
select x).Take(numberOfSymbolsCoarse).ToList();
dollarVolumeBySymbol.Clear();
foreach (var x in sortedByDollarVolume)
{
dollarVolumeBySymbol[x.Symbol] = x.DollarVolume;
}
// If no security has met the QC500 criteria, the universe is unchanged.
// A new selection will be attempted on the next trading day as lastMonth is not updated
if (dollarVolumeBySymbol.Count == 0)
{
return Universe.Unchanged;
}
return dollarVolumeBySymbol.Keys;
});
return new FineFundamentalFilteredUniverse(
coarseUniverse,
fine =>
{
// The company's headquarter must in the U.S.
// The stock must be traded on either the NYSE or NASDAQ
// At least half a year since its initial public offering
// The stock's market cap must be greater than 500 million
var filteredFine =
(from x in fine
where x.CompanyReference.CountryId == "USA" &&
(x.CompanyReference.PrimaryExchangeID == "NYS" || x.CompanyReference.PrimaryExchangeID == "NAS") &&
(_algorithm.Time - x.SecurityReference.IPODate).Days > 180 &&
x.MarketCap > 500000000m
select x).ToList();
var count = filteredFine.Count;
// If no security has met the QC500 criteria, the universe is unchanged.
// A new selection will be attempted on the next trading day as lastMonth is not updated
if (count == 0)
{
return Universe.Unchanged;
}
// Update _lastMonth after all QC500 criteria checks passed
lastMonth = _algorithm.Time.Month;
var percent = numberOfSymbolsFine / (double)count;
// select stocks with top dollar volume in every single sector
var topFineBySector =
(from x in filteredFine
// Group by sector
group x by x.CompanyReference.IndustryTemplateCode into g
let y = from item in g
orderby dollarVolumeBySymbol[item.Symbol] descending
select item
let c = (int)Math.Ceiling(y.Count() * percent)
select new { g.Key, Value = y.Take(c) }
).ToDictionary(x => x.Key, x => x.Value);
return topFineBySector.SelectMany(x => x.Value)
.OrderByDescending(x => dollarVolumeBySymbol[x.Symbol])
.Take(numberOfSymbolsFine)
.Select(x => x.Symbol);
});
}
}
}
}

View File

@@ -11,9 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Algorithm")
from QuantConnect.Algorithm.Framework.Portfolio import *
from AlgorithmImports import *
class NullPortfolioConstructionModel(PortfolioConstructionModel):
'''Provides an implementation of IPortfolioConstructionModel that does nothing'''

View File

@@ -14,14 +14,14 @@
*/
using System;
using System.Collections.Generic;
using System.Linq;
using NodaTime;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Util;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using QuantConnect.Util;
using QuantConnect.Data.Market;
using System.Collections.Generic;
namespace QuantConnect.Algorithm
{
@@ -458,104 +458,88 @@ namespace QuantConnect.Algorithm
return History(requests, TimeZone).Memoize();
}
/// <summary>
/// Yields data to warmup a security for all it's subscribed data types
/// </summary>
/// <param name="security"><see cref="Security"/> object for which to retrieve historical data</param>
/// <returns>Securities historical data</returns>
public IEnumerable<BaseData> GetLastKnownPrices(Security security)
{
return GetLastKnownPrices(security.Symbol);
}
/// <summary>
/// Yields data to warmup a security for all it's subscribed data types
/// </summary>
/// <param name="symbol">The symbol we want to get seed data for</param>
/// <returns>Securities historical data</returns>
public IEnumerable<BaseData> GetLastKnownPrices(Symbol symbol)
{
if (symbol.IsCanonical() || HistoryProvider == null)
{
return Enumerable.Empty<BaseData>();
}
var result = new Dictionary<TickType, BaseData>();
// For speed and memory usage, use Resolution.Minute as the minimum resolution
var resolution = (Resolution)Math.Max((int)Resolution.Minute,
(int)SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(symbol).GetHighestResolution());
Func<int, bool> requestData = period =>
{
var historyRequests = CreateBarCountHistoryRequests(new[] { symbol }, period, resolution)
.Select(request =>
{
// force no fill forward behavior
request.FillForwardResolution = null;
return request;
})
// request only those tick types we didn't get the data we wanted
.Where(request => !result.ContainsKey(request.TickType))
.ToList();
foreach (var slice in History(historyRequests))
{
for (var i = 0; i < historyRequests.Count; i++)
{
var historyRequest = historyRequests[i];
var data = slice.Get(historyRequest.DataType);
if (data.ContainsKey(symbol))
{
// keep the last data point per tick type
result[historyRequest.TickType] = (BaseData)data[symbol];
}
}
}
// true when all history requests tick types have a data point
return historyRequests.All(request => result.ContainsKey(request.TickType));
};
if (!requestData(5))
{
// If the first attempt to get the last know price returns null, it maybe the case of an illiquid security.
// We increase the look-back period for this case accordingly to the resolution to cover 3 trading days
var periods =
resolution == Resolution.Daily ? 3 :
resolution == Resolution.Hour ? 24 : 1440;
requestData(periods);
}
// return the data ordered by time ascending
return result.Values.OrderBy(data => data.Time);
}
/// <summary>
/// Get the last known price using the history provider.
/// Useful for seeding securities with the correct price
/// </summary>
/// <param name="security"><see cref="Security"/> object for which to retrieve historical data</param>
/// <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")]
public BaseData GetLastKnownPrice(Security security)
{
if (security.Symbol.IsCanonical() || HistoryProvider == null)
{
return null;
}
var configs = SubscriptionManager.SubscriptionDataConfigService
.GetSubscriptionDataConfigs(security.Symbol);
var dataTimeZone = MarketHoursDatabase
.GetDataTimeZone(security.Symbol.ID.Market, security.Symbol, security.Symbol.SecurityType);
// For speed and memory usage, use Resolution.Minute as the minimum resolution
var resolution = (Resolution)Math.Max((int)Resolution.Minute, (int)configs.GetHighestResolution());
var isExtendedMarketHours = configs.IsExtendedMarketHours();
// request QuoteBar for Futures and all option types
var dataType = typeof(BaseData);
if (security.Type.IsOption() || security.Type == SecurityType.Future)
{
dataType = LeanData.GetDataType(resolution, TickType.Quote);
}
// Get the config with the largest resolution
var subscriptionDataConfig = GetMatchingSubscription(security.Symbol, dataType);
TickType tickType;
if (subscriptionDataConfig == null)
{
dataType = typeof(TradeBar);
tickType = LeanData.GetCommonTickTypeForCommonDataTypes(dataType, security.Type);
}
else
{
// if subscription resolution is Tick, we also need to update the data type from Tick to TradeBar/QuoteBar
if (subscriptionDataConfig.Resolution == Resolution.Tick)
{
dataType = LeanData.GetDataType(resolution, subscriptionDataConfig.TickType);
subscriptionDataConfig = new SubscriptionDataConfig(subscriptionDataConfig, dataType, resolution: resolution);
}
dataType = subscriptionDataConfig.Type;
tickType = subscriptionDataConfig.TickType;
}
Func<int, BaseData> getLastKnownPriceForPeriods = backwardsPeriods =>
{
var startTimeUtc = _historyRequestFactory
.GetStartTimeAlgoTz(security.Symbol, backwardsPeriods, resolution, security.Exchange.Hours, dataTimeZone)
.ConvertToUtc(_localTimeKeeper.TimeZone);
var request = new HistoryRequest(
startTimeUtc,
UtcTime,
dataType,
security.Symbol,
resolution,
security.Exchange.Hours,
dataTimeZone,
resolution,
isExtendedMarketHours,
configs.IsCustomData(),
configs.DataNormalizationMode(),
tickType
);
BaseData result = null;
History(new List<HistoryRequest> { request })
.PushThrough(bar =>
{
if (!bar.IsFillForward)
result = bar;
});
return result;
};
var lastKnownPrice = getLastKnownPriceForPeriods(1);
if (lastKnownPrice != null)
{
return lastKnownPrice;
}
// If the first attempt to get the last know price returns null, it maybe the case of an illiquid security.
// We increase the look-back period for this case accordingly to the resolution to cover 3 trading days
var periods =
resolution == Resolution.Daily ? 3 :
resolution == Resolution.Hour ? 24 : 1440;
return getLastKnownPriceForPeriods(periods);
return GetLastKnownPrices(security.Symbol)
// since we are returning a single data point let's respect order
.OrderByDescending(data => GetTickTypeOrder(data.Symbol.SecurityType, LeanData.GetCommonTickTypeForCommonDataTypes(data.GetType(), data.Symbol.SecurityType)))
.LastOrDefault();
}
/// <summary>
@@ -668,16 +652,26 @@ namespace QuantConnect.Algorithm
return GetMatchingSubscriptions(symbol, type, resolution).FirstOrDefault();
}
private int GetTickTypeOrder(SecurityType securityType, TickType tickType)
{
return SubscriptionManager.AvailableDataTypes[securityType].IndexOf(tickType);
}
private IEnumerable<SubscriptionDataConfig> GetMatchingSubscriptions(Symbol symbol, Type type, Resolution? resolution = null)
{
Security security;
if (Securities.TryGetValue(symbol, out security))
{
var matchingSubscriptions = SubscriptionManager.SubscriptionDataConfigService
.GetSubscriptionDataConfigs(symbol, includeInternalConfigs:true)
// find all subscriptions matching the requested type with a higher resolution than requested
var matchingSubscriptions = from sub in security.Subscriptions.OrderByDescending(s => s.Resolution)
where SubscriptionDataConfigTypeFilter(type, sub.Type)
select sub;
.OrderByDescending(s => s.Resolution)
// lets make sure to respect the order of the data types
.ThenByDescending(config => GetTickTypeOrder(config.SecurityType, config.TickType))
.ThenBy(config => config.IsInternalFeed ? 1 : 0)
.Where(s => SubscriptionDataConfigTypeFilter(type, s.Type))
.ToList();
// we use the subscription manager registered configurations here, we can not rely on the Securities collection
// since this might be called when creating a security and warming it up
if (matchingSubscriptions.Count != 0)
{
if (resolution.HasValue
&& (resolution == Resolution.Daily || resolution == Resolution.Hour)
&& symbol.SecurityType == SecurityType.Equity)
@@ -685,7 +679,7 @@ namespace QuantConnect.Algorithm
// for Daily and Hour resolution, for equities, we have to
// filter out any existing subscriptions that could be of Quote type
// This could happen if they were Resolution.Minute/Second/Tick
matchingSubscriptions = matchingSubscriptions.Where(s => s.TickType != TickType.Quote);
return matchingSubscriptions.Where(s => s.TickType != TickType.Quote);
}
return matchingSubscriptions;

View File

@@ -1027,6 +1027,56 @@ namespace QuantConnect.Algorithm
return meanAbsoluteDeviation;
}
/// <summary>
/// Creates an Market Profile indicator for the symbol with Volume Profile (VOL) mode. The indicator will be automatically
/// updated on the given resolution.
/// </summary>
/// <param name="symbol">The symbol whose VP we want</param>
/// <param name="period">The period of the VP</param>
/// <param name="valueAreaVolumePercentage">The percentage of volume contained in the value area</param>
/// <param name="priceRangeRoundOff">How many digits you want to round and the precision. i.e 0.01 round to two digits exactly.</param>
/// <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>
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);
var marketProfile = new VolumeProfile(name, period, valueAreaVolumePercentage, priceRangeRoundOff);
RegisterIndicator(symbol, marketProfile, resolution, selector);
if (EnableAutomaticIndicatorWarmUp)
{
WarmUpIndicator(symbol, marketProfile, resolution);
}
return marketProfile;
}
/// <summary>
/// Creates an Market Profile indicator for the symbol with Time Price Opportunity (TPO) mode. The indicator will be automatically
/// updated on the given resolution.
/// </summary>
/// <param name="symbol">The symbol whose TP we want</param>
/// <param name="period">The period of the TP</param>
/// <param name="valueAreaVolumePercentage">The percentage of volume contained in the value area</param>
/// <param name="priceRangeRoundOff">How many digits you want to round and the precision. i.e 0.01 round to two digits exactly.</param>
/// <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>
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);
var marketProfile = new TimeProfile(name, period, valueAreaVolumePercentage, priceRangeRoundOff);
RegisterIndicator(symbol, marketProfile, resolution, selector);
if (EnableAutomaticIndicatorWarmUp)
{
WarmUpIndicator(symbol, marketProfile, resolution);
}
return marketProfile;
}
/// <summary>
/// Creates a new Maximum indicator to compute the maximum value
/// </summary>

View File

@@ -268,8 +268,7 @@ namespace QuantConnect.Algorithm
extendedMarketHours: true);
var security = Securities.CreateSecurity(symbol, config, leverage, addToSymbolCache: false);
AddToUserDefinedUniverse(security, new List<SubscriptionDataConfig> { config });
return security;
return AddToUserDefinedUniverse(security, new List<SubscriptionDataConfig> { config });
}
/// <summary>

View File

@@ -14,21 +14,21 @@
*/
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Interfaces;
using QuantConnect.Orders;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using System.Collections.Generic;
using QuantConnect.Securities.Option;
using static QuantConnect.StringExtensions;
using QuantConnect.Algorithm.Framework.Portfolio;
namespace QuantConnect.Algorithm
{
public partial class QCAlgorithm
{
private int _maxOrders = 10000;
private bool _isMarketOnOpenOrderWarningSent = false;
private bool _isMarketOnOpenOrderWarningSent;
/// <summary>
/// Transaction Manager - Process transaction fills and order management.
@@ -41,6 +41,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">string Symbol of the asset to trade</param>
/// <param name="quantity">int Quantity of the asset to trade</param>
/// <seealso cref="Buy(Symbol, double)"/>
/// <returns>The order ticket instance.</returns>
public OrderTicket Buy(Symbol symbol, int quantity)
{
return Order(symbol, (decimal)Math.Abs(quantity));
@@ -52,6 +53,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">string Symbol of the asset to trade</param>
/// <param name="quantity">double Quantity of the asset to trade</param>
/// <seealso cref="Buy(Symbol, decimal)"/>
/// <returns>The order ticket instance.</returns>
public OrderTicket Buy(Symbol symbol, double quantity)
{
return Order(symbol, Math.Abs(quantity).SafeDecimalCast());
@@ -63,6 +65,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">string Symbol of the asset to trade</param>
/// <param name="quantity">decimal Quantity of the asset to trade</param>
/// <seealso cref="Order(Symbol, int)"/>
/// <returns>The order ticket instance.</returns>
public OrderTicket Buy(Symbol symbol, decimal quantity)
{
return Order(symbol, Math.Abs(quantity));
@@ -74,6 +77,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">string Symbol of the asset to trade</param>
/// <param name="quantity">float Quantity of the asset to trade</param>
/// <seealso cref="Buy(Symbol, decimal)"/>
/// <returns>The order ticket instance.</returns>
public OrderTicket Buy(Symbol symbol, float quantity)
{
return Order(symbol, (decimal)Math.Abs(quantity));
@@ -86,6 +90,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">string Symbol of the asset to trade</param>
/// <param name="quantity">int Quantity of the asset to trade</param>
/// <seealso cref="Sell(Symbol, decimal)"/>
/// <returns>The order ticket instance.</returns>
public OrderTicket Sell(Symbol symbol, int quantity)
{
return Order(symbol, (decimal)Math.Abs(quantity) * -1);
@@ -96,7 +101,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="symbol">String symbol to sell</param>
/// <param name="quantity">Quantity to order</param>
/// <returns>int Order Id.</returns>
/// <returns>The order ticket instance.</returns>
public OrderTicket Sell(Symbol symbol, double quantity)
{
return Order(symbol, Math.Abs(quantity).SafeDecimalCast() * -1m);
@@ -107,7 +112,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="symbol">String symbol</param>
/// <param name="quantity">Quantity to sell</param>
/// <returns>int order id</returns>
/// <returns>The order ticket instance.</returns>
public OrderTicket Sell(Symbol symbol, float quantity)
{
return Order(symbol, (decimal)Math.Abs(quantity) * -1m);
@@ -118,7 +123,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="symbol">String symbol to sell</param>
/// <param name="quantity">Quantity to sell</param>
/// <returns>Int Order Id.</returns>
/// <returns>The order ticket instance.</returns>
public OrderTicket Sell(Symbol symbol, decimal quantity)
{
return Order(symbol, Math.Abs(quantity) * -1);
@@ -127,7 +132,10 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Issue an order/trade for asset: Alias wrapper for Order(string, int);
/// </summary>
/// <param name="symbol">Symbol to order</param>
/// <param name="quantity">Quantity to order</param>
/// <seealso cref="Order(Symbol, decimal)"/>
/// <returns>The order ticket instance.</returns>
public OrderTicket Order(Symbol symbol, double quantity)
{
return Order(symbol, quantity.SafeDecimalCast());
@@ -136,7 +144,9 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Issue an order/trade for asset
/// </summary>
/// <remarks></remarks>
/// <param name="symbol">Symbol to order</param>
/// <param name="quantity">Quantity to order</param>
/// <returns>The order ticket instance.</returns>
public OrderTicket Order(Symbol symbol, int quantity)
{
return MarketOrder(symbol, (decimal)quantity);
@@ -145,7 +155,9 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Issue an order/trade for asset
/// </summary>
/// <remarks></remarks>
/// <param name="symbol">Symbol to order</param>
/// <param name="quantity">Quantity to order</param>
/// <returns>The order ticket instance.</returns>
public OrderTicket Order(Symbol symbol, decimal quantity)
{
return MarketOrder(symbol, quantity);
@@ -158,10 +170,12 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Number of shares to request.</param>
/// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
/// <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>
/// <seealso cref="MarketOrder(Symbol, decimal, bool, string)"/>
public OrderTicket Order(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "")
public OrderTicket Order(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOrder(symbol, quantity, asynchronous, tag);
return MarketOrder(symbol, quantity, asynchronous, tag, orderProperties);
}
/// <summary>
@@ -171,10 +185,11 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Number of shares to request.</param>
/// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <returns>int Order id</returns>
public OrderTicket MarketOrder(Symbol symbol, int quantity, bool asynchronous = false, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket MarketOrder(Symbol symbol, int quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOrder(symbol, (decimal)quantity, asynchronous, tag);
return MarketOrder(symbol, (decimal)quantity, asynchronous, tag, orderProperties);
}
/// <summary>
@@ -184,10 +199,11 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Number of shares to request.</param>
/// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <returns>int Order id</returns>
public OrderTicket MarketOrder(Symbol symbol, double quantity, bool asynchronous = false, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket MarketOrder(Symbol symbol, double quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOrder(symbol, quantity.SafeDecimalCast(), asynchronous, tag);
return MarketOrder(symbol, quantity.SafeDecimalCast(), asynchronous, tag, orderProperties);
}
/// <summary>
@@ -197,11 +213,25 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Number of shares to request.</param>
/// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <returns>int Order id</returns>
public OrderTicket MarketOrder(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket MarketOrder(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
return MarketOrder(security, quantity, asynchronous, tag, orderProperties);
}
/// <summary>
/// Market order implementation: Send a market order and wait for it to be filled.
/// </summary>
/// <param name="security">Symbol of the MarketType Required.</param>
/// <param name="quantity">Number of shares to request.</param>
/// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
/// <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>
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
// then convert it into a market on open order
if (!security.Exchange.ExchangeOpen)
@@ -219,7 +249,7 @@ namespace QuantConnect.Algorithm
return mooTicket;
}
var request = CreateSubmitOrderRequest(OrderType.Market, security, quantity, tag, DefaultOrderProperties?.Clone());
var request = CreateSubmitOrderRequest(OrderType.Market, security, quantity, tag, orderProperties ?? DefaultOrderProperties?.Clone());
// If warming up, do not submit
if (IsWarmingUp)
@@ -252,10 +282,11 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">The symbol to be ordered</param>
/// <param name="quantity">The number of shares to required</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <returns>The order ID</returns>
public OrderTicket MarketOnOpenOrder(Symbol symbol, double quantity, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket MarketOnOpenOrder(Symbol symbol, double quantity, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOnOpenOrder(symbol, quantity.SafeDecimalCast(), tag);
return MarketOnOpenOrder(symbol, quantity.SafeDecimalCast(), tag, orderProperties);
}
/// <summary>
@@ -264,10 +295,11 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">The symbol to be ordered</param>
/// <param name="quantity">The number of shares to required</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <returns>The order ID</returns>
public OrderTicket MarketOnOpenOrder(Symbol symbol, int quantity, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket MarketOnOpenOrder(Symbol symbol, int quantity, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOnOpenOrder(symbol, (decimal)quantity, tag);
return MarketOnOpenOrder(symbol, (decimal)quantity, tag, orderProperties);
}
/// <summary>
@@ -276,11 +308,12 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">The symbol to be ordered</param>
/// <param name="quantity">The number of shares to required</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <returns>The order ID</returns>
public OrderTicket MarketOnOpenOrder(Symbol symbol, decimal quantity, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket MarketOnOpenOrder(Symbol symbol, decimal quantity, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
var request = CreateSubmitOrderRequest(OrderType.MarketOnOpen, security, quantity, tag, DefaultOrderProperties?.Clone());
var request = CreateSubmitOrderRequest(OrderType.MarketOnOpen, security, quantity, tag, orderProperties ?? DefaultOrderProperties?.Clone());
var response = PreOrderChecks(request);
if (response.IsError)
{
@@ -296,10 +329,11 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">The symbol to be ordered</param>
/// <param name="quantity">The number of shares to required</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <returns>The order ID</returns>
public OrderTicket MarketOnCloseOrder(Symbol symbol, int quantity, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket MarketOnCloseOrder(Symbol symbol, int quantity, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOnCloseOrder(symbol, (decimal)quantity, tag);
return MarketOnCloseOrder(symbol, (decimal)quantity, tag, orderProperties);
}
/// <summary>
@@ -308,10 +342,11 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">The symbol to be ordered</param>
/// <param name="quantity">The number of shares to required</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <returns>The order ID</returns>
public OrderTicket MarketOnCloseOrder(Symbol symbol, double quantity, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket MarketOnCloseOrder(Symbol symbol, double quantity, string tag = "", IOrderProperties orderProperties = null)
{
return MarketOnCloseOrder(symbol, quantity.SafeDecimalCast(), tag);
return MarketOnCloseOrder(symbol, quantity.SafeDecimalCast(), tag, orderProperties);
}
/// <summary>
@@ -320,11 +355,12 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">The symbol to be ordered</param>
/// <param name="quantity">The number of shares to required</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <returns>The order ID</returns>
public OrderTicket MarketOnCloseOrder(Symbol symbol, decimal quantity, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket MarketOnCloseOrder(Symbol symbol, decimal quantity, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
var request = CreateSubmitOrderRequest(OrderType.MarketOnClose, security, quantity, tag, DefaultOrderProperties?.Clone());
var request = CreateSubmitOrderRequest(OrderType.MarketOnClose, security, quantity, tag, orderProperties ?? DefaultOrderProperties?.Clone());
var response = PreOrderChecks(request);
if (response.IsError)
{
@@ -341,10 +377,11 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity of shares for limit order</param>
/// <param name="limitPrice">Limit price to fill this order</param>
/// <param name="tag">String tag for the order (optional)</param>
/// <returns>Order id</returns>
public OrderTicket LimitOrder(Symbol symbol, int quantity, decimal limitPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket LimitOrder(Symbol symbol, int quantity, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return LimitOrder(symbol, (decimal)quantity, limitPrice, tag);
return LimitOrder(symbol, (decimal)quantity, limitPrice, tag, orderProperties);
}
/// <summary>
@@ -354,10 +391,11 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity of shares for limit order</param>
/// <param name="limitPrice">Limit price to fill this order</param>
/// <param name="tag">String tag for the order (optional)</param>
/// <returns>Order id</returns>
public OrderTicket LimitOrder(Symbol symbol, double quantity, decimal limitPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket LimitOrder(Symbol symbol, double quantity, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return LimitOrder(symbol, quantity.SafeDecimalCast(), limitPrice, tag);
return LimitOrder(symbol, quantity.SafeDecimalCast(), limitPrice, tag, orderProperties);
}
/// <summary>
@@ -367,11 +405,12 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity of shares for limit order</param>
/// <param name="limitPrice">Limit price to fill this order</param>
/// <param name="tag">String tag for the order (optional)</param>
/// <returns>Order id</returns>
public OrderTicket LimitOrder(Symbol symbol, decimal quantity, decimal limitPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket LimitOrder(Symbol symbol, decimal quantity, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
var request = CreateSubmitOrderRequest(OrderType.Limit, security, quantity, tag, limitPrice: limitPrice, properties: DefaultOrderProperties?.Clone());
var request = CreateSubmitOrderRequest(OrderType.Limit, security, quantity, tag, limitPrice: limitPrice, properties: orderProperties ?? DefaultOrderProperties?.Clone());
var response = PreOrderChecks(request);
if (response.IsError)
{
@@ -388,10 +427,11 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity to be traded</param>
/// <param name="stopPrice">Price to fill the stop order</param>
/// <param name="tag">Optional string data tag for the order</param>
/// <returns>Int orderId for the new order.</returns>
public OrderTicket StopMarketOrder(Symbol symbol, int quantity, decimal stopPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket StopMarketOrder(Symbol symbol, int quantity, decimal stopPrice, string tag = "", IOrderProperties orderProperties = null)
{
return StopMarketOrder(symbol, (decimal)quantity, stopPrice, tag);
return StopMarketOrder(symbol, (decimal)quantity, stopPrice, tag, orderProperties);
}
/// <summary>
@@ -401,10 +441,11 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity to be traded</param>
/// <param name="stopPrice">Price to fill the stop order</param>
/// <param name="tag">Optional string data tag for the order</param>
/// <returns>Int orderId for the new order.</returns>
public OrderTicket StopMarketOrder(Symbol symbol, double quantity, decimal stopPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket StopMarketOrder(Symbol symbol, double quantity, decimal stopPrice, string tag = "", IOrderProperties orderProperties = null)
{
return StopMarketOrder(symbol, quantity.SafeDecimalCast(), stopPrice, tag);
return StopMarketOrder(symbol, quantity.SafeDecimalCast(), stopPrice, tag, orderProperties);
}
/// <summary>
@@ -414,11 +455,12 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity to be traded</param>
/// <param name="stopPrice">Price to fill the stop order</param>
/// <param name="tag">Optional string data tag for the order</param>
/// <returns>Int orderId for the new order.</returns>
public OrderTicket StopMarketOrder(Symbol symbol, decimal quantity, decimal stopPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket StopMarketOrder(Symbol symbol, decimal quantity, decimal stopPrice, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
var request = CreateSubmitOrderRequest(OrderType.StopMarket, security, quantity, tag, stopPrice: stopPrice, properties: DefaultOrderProperties?.Clone());
var request = CreateSubmitOrderRequest(OrderType.StopMarket, security, quantity, tag, stopPrice: stopPrice, properties: orderProperties ?? DefaultOrderProperties?.Clone());
var response = PreOrderChecks(request);
if (response.IsError)
{
@@ -436,10 +478,11 @@ namespace QuantConnect.Algorithm
/// <param name="stopPrice">Stop price for this order</param>
/// <param name="limitPrice">Limit price to fill this order</param>
/// <param name="tag">String tag for the order (optional)</param>
/// <returns>Order id</returns>
public OrderTicket StopLimitOrder(Symbol symbol, int quantity, decimal stopPrice, decimal limitPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket StopLimitOrder(Symbol symbol, int quantity, decimal stopPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return StopLimitOrder(symbol, (decimal)quantity, stopPrice, limitPrice, tag);
return StopLimitOrder(symbol, (decimal)quantity, stopPrice, limitPrice, tag, orderProperties);
}
/// <summary>
@@ -450,10 +493,11 @@ namespace QuantConnect.Algorithm
/// <param name="stopPrice">Stop price for this order</param>
/// <param name="limitPrice">Limit price to fill this order</param>
/// <param name="tag">String tag for the order (optional)</param>
/// <returns>Order id</returns>
public OrderTicket StopLimitOrder(Symbol symbol, double quantity, decimal stopPrice, decimal limitPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket StopLimitOrder(Symbol symbol, double quantity, decimal stopPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return StopLimitOrder(symbol, quantity.SafeDecimalCast(), stopPrice, limitPrice, tag);
return StopLimitOrder(symbol, quantity.SafeDecimalCast(), stopPrice, limitPrice, tag, orderProperties);
}
/// <summary>
@@ -464,11 +508,12 @@ namespace QuantConnect.Algorithm
/// <param name="stopPrice">Stop price for this order</param>
/// <param name="limitPrice">Limit price to fill this order</param>
/// <param name="tag">String tag for the order (optional)</param>
/// <returns>Order id</returns>
public OrderTicket StopLimitOrder(Symbol symbol, decimal quantity, decimal stopPrice, decimal limitPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket StopLimitOrder(Symbol symbol, decimal quantity, decimal stopPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
var request = CreateSubmitOrderRequest(OrderType.StopLimit, security, quantity, tag, stopPrice: stopPrice, limitPrice: limitPrice, properties: DefaultOrderProperties?.Clone());
var request = CreateSubmitOrderRequest(OrderType.StopLimit, security, quantity, tag, stopPrice: stopPrice, limitPrice: limitPrice, properties: orderProperties ?? DefaultOrderProperties?.Clone());
var response = PreOrderChecks(request);
if (response.IsError)
{
@@ -487,10 +532,11 @@ namespace QuantConnect.Algorithm
/// <param name="triggerPrice">Trigger price for this order</param>
/// <param name="limitPrice">Limit price to fill this order</param>
/// <param name="tag">String tag for the order (optional)</param>
/// <returns>Order id</returns>
public OrderTicket LimitIfTouchedOrder(Symbol symbol, int quantity, decimal triggerPrice, decimal limitPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket LimitIfTouchedOrder(Symbol symbol, int quantity, decimal triggerPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return LimitIfTouchedOrder(symbol, (decimal)quantity, triggerPrice, limitPrice, tag);
return LimitIfTouchedOrder(symbol, (decimal)quantity, triggerPrice, limitPrice, tag, orderProperties);
}
/// <summary>
@@ -501,10 +547,11 @@ namespace QuantConnect.Algorithm
/// <param name="triggerPrice">Trigger price for this order</param>
/// <param name="limitPrice">Limit price to fill this order</param>
/// <param name="tag">String tag for the order (optional)</param>
/// <returns>Order id</returns>
public OrderTicket LimitIfTouchedOrder(Symbol symbol, double quantity, decimal triggerPrice, decimal limitPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket LimitIfTouchedOrder(Symbol symbol, double quantity, decimal triggerPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
return LimitIfTouchedOrder(symbol, quantity.SafeDecimalCast(), triggerPrice, limitPrice, tag);
return LimitIfTouchedOrder(symbol, quantity.SafeDecimalCast(), triggerPrice, limitPrice, tag, orderProperties);
}
/// <summary>
@@ -515,11 +562,12 @@ namespace QuantConnect.Algorithm
/// <param name="triggerPrice">Trigger price for this order</param>
/// <param name="limitPrice">Limit price to fill this order</param>
/// <param name="tag">String tag for the order (optional)</param>
/// <returns>Order id</returns>
public OrderTicket LimitIfTouchedOrder(Symbol symbol, decimal quantity, decimal triggerPrice, decimal limitPrice, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket LimitIfTouchedOrder(Symbol symbol, decimal quantity, decimal triggerPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
{
var security = Securities[symbol];
var request = CreateSubmitOrderRequest(OrderType.LimitIfTouched, security, quantity, tag, triggerPrice: triggerPrice, limitPrice: limitPrice, properties: DefaultOrderProperties?.Clone());
var request = CreateSubmitOrderRequest(OrderType.LimitIfTouched, security, quantity, tag, triggerPrice: triggerPrice, limitPrice: limitPrice, properties: orderProperties ?? DefaultOrderProperties?.Clone());
var response = PreOrderChecks(request);
if (response.IsError)
{
@@ -537,13 +585,15 @@ namespace QuantConnect.Algorithm
/// <param name="quantity">Quantity of options contracts</param>
/// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
/// <param name="tag">String tag for the order (optional)</param>
public OrderTicket ExerciseOption(Symbol optionSymbol, int quantity, bool asynchronous = false, string tag = "")
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>The order ticket instance.</returns>
public OrderTicket ExerciseOption(Symbol optionSymbol, int quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
var option = (Option) Securities[optionSymbol];
// SubmitOrderRequest.Quantity indicates the change in holdings quantity, therefore manual exercise quantities must be negative
// PreOrderChecksImpl confirms that we don't hold a short position, so we're lenient here and accept +/- quantity values
var request = CreateSubmitOrderRequest(OrderType.OptionExercise, option, -Math.Abs(quantity), tag, DefaultOrderProperties?.Clone());
var request = CreateSubmitOrderRequest(OrderType.OptionExercise, option, -Math.Abs(quantity), tag, orderProperties ?? DefaultOrderProperties?.Clone());
// If warming up, do not submit
if (IsWarmingUp)
@@ -577,10 +627,11 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="strategy">Specification of the strategy to trade</param>
/// <param name="quantity">Quantity of the strategy to trade</param>
/// <returns>Sequence of order ids</returns>
public IEnumerable<OrderTicket> Buy(OptionStrategy strategy, int quantity)
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>Sequence of order tickets</returns>
public IEnumerable<OrderTicket> Buy(OptionStrategy strategy, int quantity, IOrderProperties orderProperties = null)
{
return Order(strategy, Math.Abs(quantity));
return Order(strategy, Math.Abs(quantity), orderProperties);
}
/// <summary>
@@ -588,10 +639,11 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="strategy">Specification of the strategy to trade</param>
/// <param name="quantity">Quantity of the strategy to trade</param>
/// <returns>Sequence of order ids</returns>
public IEnumerable<OrderTicket> Sell(OptionStrategy strategy, int quantity)
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>Sequence of order tickets</returns>
public IEnumerable<OrderTicket> Sell(OptionStrategy strategy, int quantity, IOrderProperties orderProperties = null)
{
return Order(strategy, Math.Abs(quantity) * -1);
return Order(strategy, Math.Abs(quantity) * -1, orderProperties);
}
/// <summary>
@@ -599,13 +651,14 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="strategy">Specification of the strategy to trade</param>
/// <param name="quantity">Quantity of the strategy to trade</param>
/// <returns>Sequence of order ids</returns>
public IEnumerable<OrderTicket> Order(OptionStrategy strategy, int quantity)
/// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
/// <returns>Sequence of order tickets</returns>
public IEnumerable<OrderTicket> Order(OptionStrategy strategy, int quantity, IOrderProperties orderProperties = null)
{
return GenerateOrders(strategy, quantity);
return GenerateOrders(strategy, quantity, orderProperties);
}
private IEnumerable<OrderTicket> GenerateOrders(OptionStrategy strategy, int strategyQuantity)
private IEnumerable<OrderTicket> GenerateOrders(OptionStrategy strategy, int strategyQuantity, IOrderProperties orderProperties = null)
{
var orders = new List<OrderTicket>();
@@ -638,11 +691,11 @@ namespace QuantConnect.Algorithm
switch (optionLeg.OrderType)
{
case OrderType.Market:
orders.Add(MarketOrder(contract.Symbol, orderQuantity, tag: tag));
orders.Add(MarketOrder(contract.Symbol, orderQuantity, tag: tag, orderProperties: orderProperties));
break;
case OrderType.Limit:
orders.Add(LimitOrder(contract.Symbol, orderQuantity, optionLeg.OrderPrice, tag));
orders.Add(LimitOrder(contract.Symbol, orderQuantity, optionLeg.OrderPrice, tag, orderProperties));
break;
default:
@@ -667,11 +720,11 @@ namespace QuantConnect.Algorithm
switch (underlyingLeg.OrderType)
{
case OrderType.Market:
orders.Add(MarketOrder(strategy.Underlying, orderQuantity, tag: tag));
orders.Add(MarketOrder(strategy.Underlying, orderQuantity, tag: tag, orderProperties: orderProperties));
break;
case OrderType.Limit:
orders.Add(LimitOrder(strategy.Underlying, orderQuantity, underlyingLeg.OrderPrice, tag));
orders.Add(LimitOrder(strategy.Underlying, orderQuantity, underlyingLeg.OrderPrice, tag, orderProperties));
break;
default:
@@ -959,15 +1012,17 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="targets">The portfolio desired quantities as percentages</param>
/// <param name="liquidateExistingHoldings">True will liquidate existing holdings</param>
/// <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)"/>
public void SetHoldings(List<PortfolioTarget> targets, bool liquidateExistingHoldings = false)
public void SetHoldings(List<PortfolioTarget> targets, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
foreach (var portfolioTarget in targets
// we need to create targets with quantities for OrderTargetsByMarginImpact
.Select(target => new PortfolioTarget(target.Symbol, CalculateOrderQuantity(target.Symbol, target.Quantity)))
.OrderTargetsByMarginImpact(this, targetIsDelta:true))
{
SetHoldingsImpl(portfolioTarget.Symbol, portfolioTarget.Quantity, liquidateExistingHoldings);
SetHoldingsImpl(portfolioTarget.Symbol, portfolioTarget.Quantity, liquidateExistingHoldings, tag, orderProperties);
}
}
@@ -977,10 +1032,12 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">string symbol we wish to hold</param>
/// <param name="percentage">double percentage of holdings desired</param>
/// <param name="liquidateExistingHoldings">liquidate existing holdings if necessary to hold this stock</param>
/// <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)"/>
public void SetHoldings(Symbol symbol, double percentage, bool liquidateExistingHoldings = false)
public void SetHoldings(Symbol symbol, double percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
SetHoldings(symbol, percentage.SafeDecimalCast(), liquidateExistingHoldings);
SetHoldings(symbol, percentage.SafeDecimalCast(), liquidateExistingHoldings, tag, orderProperties);
}
/// <summary>
@@ -990,10 +1047,11 @@ namespace QuantConnect.Algorithm
/// <param name="percentage">float percentage of holdings desired</param>
/// <param name="liquidateExistingHoldings">bool liquidate existing holdings if necessary to hold this stock</param>
/// <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)"/>
public void SetHoldings(Symbol symbol, float percentage, bool liquidateExistingHoldings = false, string tag = "")
public void SetHoldings(Symbol symbol, float percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag);
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, orderProperties);
}
/// <summary>
@@ -1003,10 +1061,11 @@ namespace QuantConnect.Algorithm
/// <param name="percentage">float percentage of holdings desired</param>
/// <param name="liquidateExistingHoldings">bool liquidate existing holdings if necessary to hold this stock</param>
/// <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)"/>
public void SetHoldings(Symbol symbol, int percentage, bool liquidateExistingHoldings = false, string tag = "")
public void SetHoldings(Symbol symbol, int percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag);
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, orderProperties);
}
/// <summary>
@@ -1019,16 +1078,17 @@ namespace QuantConnect.Algorithm
/// <param name="percentage">decimal fraction of portfolio to set stock</param>
/// <param name="liquidateExistingHoldings">bool flag to clean all existing holdings before setting new faction.</param>
/// <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)"/>
public void SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "")
public void SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
SetHoldingsImpl(symbol, CalculateOrderQuantity(symbol, percentage), liquidateExistingHoldings, tag);
SetHoldingsImpl(symbol, CalculateOrderQuantity(symbol, percentage), liquidateExistingHoldings, tag, orderProperties);
}
/// <summary>
/// Set holdings implementation, which uses order quantities (delta) not percentage nor target final quantity
/// </summary>
private void SetHoldingsImpl(Symbol symbol, decimal orderQuantity, bool liquidateExistingHoldings = false, string tag = "")
private void SetHoldingsImpl(Symbol symbol, decimal orderQuantity, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
{
//If they triggered a liquidate
if (liquidateExistingHoldings)
@@ -1041,7 +1101,7 @@ namespace QuantConnect.Algorithm
{
//Go through all existing holdings [synchronously], market order the inverse quantity:
var liquidationQuantity = CalculateOrderQuantity(holdingSymbol, 0m);
Order(holdingSymbol, liquidationQuantity, false, tag);
Order(holdingSymbol, liquidationQuantity, false, tag, orderProperties);
}
}
}
@@ -1067,11 +1127,11 @@ namespace QuantConnect.Algorithm
//Check whether the exchange is open to send a market order. If not, send a market on open order instead
if (security.Exchange.ExchangeOpen)
{
MarketOrder(symbol, quantity, false, tag);
MarketOrder(symbol, quantity, false, tag, orderProperties);
}
else
{
MarketOnOpenOrder(symbol, quantity, tag);
MarketOnOpenOrder(symbol, quantity, tag, orderProperties);
}
}
}
@@ -1115,19 +1175,21 @@ namespace QuantConnect.Algorithm
/// <param name="type">Order Type</param>
/// <param name="asynchronous">Don't wait for the response, just submit order and move on.</param>
/// <param name="tag">Custom data for this order</param>
/// <returns>Integer Order ID.</returns>
/// <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.")]
public OrderTicket Order(Symbol symbol, int quantity, OrderType type, bool asynchronous = false, string tag = "")
public OrderTicket Order(Symbol symbol, int quantity, OrderType type, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
{
return Order(symbol, quantity, asynchronous, tag);
return Order(symbol, quantity, asynchronous, tag, orderProperties);
}
/// <summary>
/// Obsolete method for placing orders.
/// </summary>
/// <param name="symbol"></param>
/// <param name="quantity"></param>
/// <param name="type"></param>
/// <param name="symbol">Symbol we want to order</param>
/// <param name="quantity">The quantity to order</param>
/// <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.")]
public OrderTicket Order(Symbol symbol, decimal quantity, OrderType type)
{
@@ -1137,9 +1199,10 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Obsolete method for placing orders.
/// </summary>
/// <param name="symbol"></param>
/// <param name="quantity"></param>
/// <param name="type"></param>
/// <param name="symbol">Symbol we want to order</param>
/// <param name="quantity">The quantity to order</param>
/// <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.")]
public OrderTicket Order(Symbol symbol, int quantity, OrderType type)
{

View File

@@ -517,7 +517,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="security">The security to add</param>
/// <param name="configurations">The <see cref="SubscriptionDataConfig"/> instances we want to add</param>
private void AddToUserDefinedUniverse(
private Security AddToUserDefinedUniverse(
Security security,
List<SubscriptionDataConfig> configurations)
{
@@ -532,10 +532,18 @@ namespace QuantConnect.Algorithm
securityUniverse?.Remove(security.Symbol);
Securities.Remove(security.Symbol);
Securities.Add(security);
}
else
{
// we will reuse existing so we return it to the user
security = existingSecurity;
}
}
Securities.Add(security);
else
{
Securities.Add(security);
}
// add this security to the user defined universe
Universe universe;
@@ -587,6 +595,8 @@ namespace QuantConnect.Algorithm
// 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.");
}
return security;
}
/// <summary>

View File

@@ -1508,8 +1508,7 @@ namespace QuantConnect.Algorithm
return security;
}
AddToUserDefinedUniverse(security, configs);
return security;
return AddToUserDefinedUniverse(security, configs);
}
/// <summary>
@@ -2268,8 +2267,7 @@ namespace QuantConnect.Algorithm
var configs = SubscriptionManager.SubscriptionDataConfigService.Add(symbol, resolution, fillDataForward, extendedMarketHours, dataNormalizationMode: UniverseSettings.DataNormalizationMode);
var security = Securities.CreateSecurity(symbol, configs, leverage);
AddToUserDefinedUniverse(security, configs);
return (T)security;
return (T) AddToUserDefinedUniverse(security, configs);
}
/// <summary>

View File

@@ -30,7 +30,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.5" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.6" />
<PackageReference Include="MathNet.Numerics" Version="4.15.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>

View File

@@ -11,16 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Risk import *
from AlgorithmImports import *
class CompositeRiskManagementModel(RiskManagementModel):
'''Provides an implementation of IRiskManagementModel that combines multiple risk models

View File

@@ -11,9 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Algorithm")
from QuantConnect.Algorithm.Framework.Risk import *
from AlgorithmImports import *
class NullRiskManagementModel(RiskManagementModel):
'''Provides an implementation of IRiskManagementModel that does nothing'''

View File

@@ -11,17 +11,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from AlgorithmImports import *
from clr import GetClrType as typeof
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Data import *
from QuantConnect.Data.Market import *
from QuantConnect.Securities import *
from QuantConnect.Algorithm.Framework.Selection import *
from Selection.UniverseSelectionModel import UniverseSelectionModel
from itertools import groupby

View File

@@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from datetime import datetime
from AlgorithmImports import *
class UniverseSelectionModel:
'''Provides a base class for universe selection models.'''
@@ -26,4 +26,4 @@ class UniverseSelectionModel:
algorithm: The algorithm instance to create universes for</param>
Returns:
The universes to be used by the algorithm'''
raise NotImplementedError("Types deriving from 'UniverseSelectionModel' must implement the 'def CreateUniverses(QCAlgorithm) method.")
raise NotImplementedError("Types deriving from 'UniverseSelectionModel' must implement the 'def CreateUniverses(QCAlgorithm) method.")

View File

@@ -14,6 +14,11 @@
*
*/
using System;
using System.Collections.Generic;
using System.Linq;
using Python.Runtime;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
namespace QuantConnect.Algorithm
@@ -23,35 +28,298 @@ namespace QuantConnect.Algorithm
/// </summary>
public class UniverseDefinitions
{
private readonly QCAlgorithm _algorithm;
/// <summary>
/// Gets a helper that provides methods for creating universes based on daily dollar volumes
/// </summary>
public DollarVolumeUniverseDefinitions DollarVolume { get; set; }
/// <summary>
/// Specifies that universe selection should not make changes on this iteration
/// </summary>
public Universe.UnchangedUniverse Unchanged => Universe.Unchanged;
/// <summary>
/// Gets a helper that provides methods for creating universes based on daily dollar volumes
/// </summary>
public DollarVolumeUniverseDefinitions DollarVolume { get; private set; }
/// <summary>
/// Gets a helper that provides methods for creating universes based on index definitions
/// </summary>
public IndexUniverseDefinitions Index { get; private set; }
/// <summary>
/// Gets a helper that provides methods for creating constituent universes
/// </summary>
public ConstituentUniverseDefinitions Constituent { get; }
/// <summary>
/// Initializes a new instance of the <see cref="UniverseDefinitions"/> class
/// </summary>
/// <param name="algorithm">The algorithm instance, used for obtaining the default <see cref="UniverseSettings"/></param>
public UniverseDefinitions(QCAlgorithm algorithm)
{
_algorithm = algorithm;
DollarVolume = new DollarVolumeUniverseDefinitions(algorithm);
Index = new IndexUniverseDefinitions(algorithm);
Constituent = new ConstituentUniverseDefinitions(algorithm);
}
/// <summary>
/// Creates a universe for the constituents of the provided <paramref name="etfTicker"/>
/// </summary>
/// <param name="etfTicker">Ticker of the ETF to get constituents for</param>
/// <param name="market">Market of the ETF</param>
/// <param name="universeSettings">Universe settings</param>
/// <param name="universeFilterFunc">Function to filter universe results</param>
/// <returns>New ETF constituents Universe</returns>
public Universe ETF(
string etfTicker,
string market = null,
UniverseSettings universeSettings = null,
Func<IEnumerable<ETFConstituentData>, IEnumerable<Symbol>> universeFilterFunc = null)
{
market ??= _algorithm.BrokerageModel.DefaultMarkets.TryGetValue(SecurityType.Equity, out var defaultMarket)
? defaultMarket
: throw new Exception("No default market set for security type: Equity");
var etfSymbol = new Symbol(
SecurityIdentifier.GenerateEquity(
etfTicker,
market,
true,
mappingResolveDate: _algorithm.Time.Date),
etfTicker);
return ETF(etfSymbol, universeSettings, universeFilterFunc);
}
/// <summary>
/// Creates a universe for the constituents of the provided <paramref name="etfTicker"/>
/// </summary>
/// <param name="etfTicker">Ticker of the ETF to get constituents for</param>
/// <param name="market">Market of the ETF</param>
/// <param name="universeSettings">Universe settings</param>
/// <param name="universeFilterFunc">Function to filter universe results</param>
/// <returns>New ETF constituents Universe</returns>
public Universe ETF(
string etfTicker,
string market = null,
UniverseSettings universeSettings = null,
PyObject universeFilterFunc = null)
{
return ETF(etfTicker, market, universeSettings, universeFilterFunc.ConvertPythonUniverseFilterFunction<ETFConstituentData>());
}
/// <summary>
/// Creates a universe for the constituents of the provided ETF <paramref name="symbol"/>
/// </summary>
/// <param name="symbol">ETF Symbol to get constituents for</param>
/// <param name="universeSettings">Universe settings</param>
/// <param name="universeFilterFunc">Function to filter universe results</param>
/// <returns>New ETF constituents Universe</returns>
public Universe ETF(
Symbol symbol,
UniverseSettings universeSettings = null,
Func<IEnumerable<ETFConstituentData>, IEnumerable<Symbol>> universeFilterFunc = null)
{
return new ETFConstituentsUniverse(symbol, universeSettings ?? _algorithm.UniverseSettings, universeFilterFunc);
}
/// <summary>
/// Creates a universe for the constituents of the provided ETF <paramref name="symbol"/>
/// </summary>
/// <param name="symbol">ETF Symbol to get constituents for</param>
/// <param name="universeSettings">Universe settings</param>
/// <param name="universeFilterFunc">Function to filter universe results</param>
/// <returns>New ETF constituents Universe</returns>
public Universe ETF(
Symbol symbol,
UniverseSettings universeSettings = null,
PyObject universeFilterFunc = null)
{
return ETF(symbol, universeSettings, universeFilterFunc.ConvertPythonUniverseFilterFunction<ETFConstituentData>());
}
/// <summary>
/// Creates a universe for the constituents of the provided <paramref name="indexTicker"/>
/// </summary>
/// <param name="indexTicker">Ticker of the index to get constituents for</param>
/// <param name="market">Market of the index</param>
/// <param name="universeSettings">Universe settings</param>
/// <param name="universeFilterFunc">Function to filter universe results</param>
/// <returns>New index constituents Universe</returns>
public Universe Index(
string indexTicker,
string market = null,
UniverseSettings universeSettings = null,
Func<IEnumerable<ETFConstituentData>, IEnumerable<Symbol>> universeFilterFunc = null)
{
market ??= _algorithm.BrokerageModel.DefaultMarkets.TryGetValue(SecurityType.Index, out var defaultMarket)
? defaultMarket
: throw new Exception("No default market set for security type: Index");
return Index(
Symbol.Create(indexTicker, SecurityType.Index, market),
universeSettings,
universeFilterFunc);
}
/// <summary>
/// Creates a universe for the constituents of the provided <paramref name="indexTicker"/>
/// </summary>
/// <param name="indexTicker">Ticker of the index to get constituents for</param>
/// <param name="market">Market of the index</param>
/// <param name="universeSettings">Universe settings</param>
/// <param name="universeFilterFunc">Function to filter universe results</param>
/// <returns>New index constituents Universe</returns>
public Universe Index(
string indexTicker,
string market = null,
UniverseSettings universeSettings = null,
PyObject universeFilterFunc = null)
{
return Index(indexTicker, market, universeSettings, universeFilterFunc.ConvertPythonUniverseFilterFunction<ETFConstituentData>());
}
/// <summary>
/// Creates a universe for the constituents of the provided <paramref name="indexSymbol"/>
/// </summary>
/// <param name="indexSymbol">Index Symbol to get constituents for</param>
/// <param name="universeSettings">Universe settings</param>
/// <param name="universeFilterFunc">Function to filter universe results</param>
/// <returns>New index constituents Universe</returns>
public Universe Index(
Symbol indexSymbol,
UniverseSettings universeSettings = null,
Func<IEnumerable<ETFConstituentData>, IEnumerable<Symbol>> universeFilterFunc = null)
{
return new ETFConstituentsUniverse(indexSymbol, universeSettings ?? _algorithm.UniverseSettings, universeFilterFunc);
}
/// <summary>
/// Creates a universe for the constituents of the provided <paramref name="indexSymbol"/>
/// </summary>
/// <param name="indexSymbol">Index Symbol to get constituents for</param>
/// <param name="universeSettings">Universe settings</param>
/// <param name="universeFilterFunc">Function to filter universe results</param>
/// <returns>New index constituents Universe</returns>
public Universe Index(
Symbol indexSymbol,
UniverseSettings universeSettings = null,
PyObject universeFilterFunc = null)
{
return Index(indexSymbol, universeSettings, universeFilterFunc.ConvertPythonUniverseFilterFunction<ETFConstituentData>());
}
/// <summary>
/// Creates a new fine universe that contains the constituents of QC500 index based onthe company fundamentals
/// The algorithm creates a default tradable and liquid universe containing 500 US equities
/// which are chosen at the first trading day of each month.
/// </summary>
/// <returns>A new coarse universe for the top count of stocks by dollar volume</returns>
public Universe QC500
{
get
{
var lastMonth = -1;
var numberOfSymbolsCoarse = 1000;
var numberOfSymbolsFine = 500;
var dollarVolumeBySymbol = new Dictionary<Symbol, decimal>();
var symbol = Symbol.Create("qc-500", SecurityType.Equity, Market.USA);
var coarseUniverse = new CoarseFundamentalUniverse(
symbol,
_algorithm.UniverseSettings,
coarse =>
{
if (_algorithm.Time.Month == lastMonth)
{
return Universe.Unchanged;
}
// The stocks must have fundamental data
// The stock must have positive previous-day close price
// The stock must have positive volume on the previous trading day
var sortedByDollarVolume =
(from x in coarse
where x.HasFundamentalData && x.Volume > 0 && x.Price > 0
orderby x.DollarVolume descending
select x).Take(numberOfSymbolsCoarse).ToList();
dollarVolumeBySymbol.Clear();
foreach (var x in sortedByDollarVolume)
{
dollarVolumeBySymbol[x.Symbol] = x.DollarVolume;
}
// If no security has met the QC500 criteria, the universe is unchanged.
// A new selection will be attempted on the next trading day as lastMonth is not updated
if (dollarVolumeBySymbol.Count == 0)
{
return Universe.Unchanged;
}
return dollarVolumeBySymbol.Keys;
});
return new FineFundamentalFilteredUniverse(
coarseUniverse,
fine =>
{
// The company's headquarter must in the U.S.
// The stock must be traded on either the NYSE or NASDAQ
// At least half a year since its initial public offering
// The stock's market cap must be greater than 500 million
var filteredFine =
(from x in fine
where x.CompanyReference.CountryId == "USA" &&
(x.CompanyReference.PrimaryExchangeID == "NYS" ||
x.CompanyReference.PrimaryExchangeID == "NAS") &&
(_algorithm.Time - x.SecurityReference.IPODate).Days > 180 &&
x.MarketCap > 500000000m
select x).ToList();
var count = filteredFine.Count;
// If no security has met the QC500 criteria, the universe is unchanged.
// A new selection will be attempted on the next trading day as lastMonth is not updated
if (count == 0)
{
return Universe.Unchanged;
}
// Update _lastMonth after all QC500 criteria checks passed
lastMonth = _algorithm.Time.Month;
var percent = numberOfSymbolsFine / (double) count;
// select stocks with top dollar volume in every single sector
var topFineBySector =
(from x in filteredFine
// Group by sector
group x by x.CompanyReference.IndustryTemplateCode
into g
let y = from item in g
orderby dollarVolumeBySymbol[item.Symbol] descending
select item
let c = (int) Math.Ceiling(y.Count() * percent)
select new {g.Key, Value = y.Take(c)}
).ToDictionary(x => x.Key, x => x.Value);
return topFineBySector.SelectMany(x => x.Value)
.OrderByDescending(x => dollarVolumeBySymbol[x.Symbol])
.Take(numberOfSymbolsFine)
.Select(x => x.Symbol);
});
}
}
/// <summary>
/// Creates a new coarse universe that contains the top count of stocks
/// by daily dollar volume
/// </summary>
/// <param name="count">The number of stock to select</param>
/// <param name="universeSettings">The settings for stocks added by this universe.
/// Defaults to <see cref="QCAlgorithm.UniverseSettings"/></param>
/// <returns>A new coarse universe for the top count of stocks by dollar volume</returns>
public Universe Top(int count, UniverseSettings universeSettings = null)
{
universeSettings ??= _algorithm.UniverseSettings;
var symbol = Symbol.Create("us-equity-dollar-volume-top-" + count, SecurityType.Equity, Market.USA);
var config = new SubscriptionDataConfig(typeof(CoarseFundamental), symbol, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, false, false, true);
return new FuncUniverse(config, universeSettings, selectionData => (
from c in selectionData.OfType<CoarseFundamental>()
orderby c.DollarVolume descending
select c.Symbol).Take(count)
);
}
}
}

View File

@@ -29,7 +29,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.5" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.6" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -51,4 +51,4 @@
<PackagePath></PackagePath>
</None>
</ItemGroup>
</Project>
</Project>

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -12,22 +12,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace QuantConnect.Brokerages
{
/// <summary>
/// Wrapper for WebSocket4Net to enhance testability
/// </summary>
public interface IWebSocket
{
/// <summary>
/// Wraps constructor
/// </summary>
/// <param name="url"></param>
void Initialize(string url);
/// <param name="url">The target websocket url</param>
/// <param name="sessionToken">The websocket session token</param>
void Initialize(string url, string sessionToken = null);
/// <summary>
/// Wraps send method

View File

@@ -117,7 +117,7 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
{ Market.COMEX, "NYMEX" },
{ Market.CBOT, "ECBOT" },
{ Market.ICE, "NYBOT" },
{ Market.CBOE, "CFE" }
{ Market.CFE, "CFE" }
};
private readonly SymbolPropertiesDatabase _symbolPropertiesDatabase = SymbolPropertiesDatabase.FromDataFolder();

View File

@@ -38,7 +38,7 @@
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NodaTime" Version="3.0.5" />
<PackageReference Include="QuantConnect.IBAutomater" Version="2.0.52" />
<PackageReference Include="QuantConnect.IBAutomater" Version="2.0.56" />
<PackageReference Include="RestSharp" Version="106.12.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -20,6 +20,7 @@ using System.Linq;
using NodaTime;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Logging;
using HistoryRequest = QuantConnect.Data.HistoryRequest;
namespace QuantConnect.Brokerages.Tradier
@@ -81,7 +82,7 @@ namespace QuantConnect.Brokerages.Tradier
{
foreach (var request in requests)
{
if (request.Symbol.ID.SecurityType != SecurityType.Equity)
if (request.Symbol.ID.SecurityType != SecurityType.Equity && request.Symbol.ID.SecurityType != SecurityType.Option)
{
throw new ArgumentException("Invalid security type: " + request.Symbol.ID.SecurityType);
}
@@ -91,6 +92,17 @@ namespace QuantConnect.Brokerages.Tradier
throw new ArgumentException("Invalid date range specified");
}
if (request.Symbol.IsCanonical())
{
throw new ArgumentException("Invalid symbol, cannot use canonical symbols for history request");
}
if (request.DataType == typeof(QuoteBar))
{
Log.Error("TradierBrokerage.GetHistory(): Tradier only supports TradeBars");
yield break;
}
var start = request.StartTimeUtc.ConvertTo(DateTimeZone.Utc, TimeZones.NewYork);
var end = request.EndTimeUtc.ConvertTo(DateTimeZone.Utc, TimeZones.NewYork);
@@ -164,7 +176,7 @@ namespace QuantConnect.Brokerages.Tradier
private IEnumerable<Slice> GetHistoryTick(Symbol symbol, DateTime start, DateTime end)
{
var history = GetTimeSeries(symbol.Value, start, end, TradierTimeSeriesIntervals.Tick);
var history = GetTimeSeries(symbol, start, end, TradierTimeSeriesIntervals.Tick);
if (history == null)
return Enumerable.Empty<Slice>();
@@ -185,7 +197,7 @@ namespace QuantConnect.Brokerages.Tradier
private IEnumerable<Slice> GetHistorySecond(Symbol symbol, DateTime start, DateTime end)
{
var history = GetTimeSeries(symbol.Value, start, end, TradierTimeSeriesIntervals.Tick);
var history = GetTimeSeries(symbol, start, end, TradierTimeSeriesIntervals.Tick);
if (history == null)
return Enumerable.Empty<Slice>();
@@ -220,7 +232,7 @@ namespace QuantConnect.Brokerages.Tradier
private IEnumerable<Slice> GetHistoryMinute(Symbol symbol, DateTime start, DateTime end)
{
var history = GetTimeSeries(symbol.Value, start, end, TradierTimeSeriesIntervals.OneMinute);
var history = GetTimeSeries(symbol, start, end, TradierTimeSeriesIntervals.OneMinute);
if (history == null)
return Enumerable.Empty<Slice>();
@@ -234,7 +246,7 @@ namespace QuantConnect.Brokerages.Tradier
private IEnumerable<Slice> GetHistoryHour(Symbol symbol, DateTime start, DateTime end)
{
var history = GetTimeSeries(symbol.Value, start, end, TradierTimeSeriesIntervals.FifteenMinutes);
var history = GetTimeSeries(symbol, start, end, TradierTimeSeriesIntervals.FifteenMinutes);
if (history == null)
return Enumerable.Empty<Slice>();
@@ -262,7 +274,7 @@ namespace QuantConnect.Brokerages.Tradier
private IEnumerable<Slice> GetHistoryDaily(Symbol symbol, DateTime start, DateTime end)
{
var history = GetHistoricalData(symbol.Value, start, end);
var history = GetHistoricalData(symbol, start, end);
DataPointCount += history.Count;

View File

@@ -494,11 +494,12 @@ namespace QuantConnect.Brokerages.Tradier
/// <summary>
/// Get the historical bars for this period
/// </summary>
public List<TradierTimeSeries> GetTimeSeries(string symbol, DateTime start, DateTime end, TradierTimeSeriesIntervals interval)
public List<TradierTimeSeries> GetTimeSeries(Symbol symbol, DateTime start, DateTime end, TradierTimeSeriesIntervals interval)
{
//Send Request:
// Create and send request
var ticker = _symbolMapper.GetBrokerageSymbol(symbol);
var request = new RestRequest("markets/timesales", Method.GET);
request.AddParameter("symbol", symbol, ParameterType.QueryString);
request.AddParameter("symbol", ticker, ParameterType.QueryString);
request.AddParameter("interval", GetEnumDescription(interval), ParameterType.QueryString);
request.AddParameter("start", start.ToStringInvariant("yyyy-MM-dd HH:mm"), ParameterType.QueryString);
request.AddParameter("end", end.ToStringInvariant("yyyy-MM-dd HH:mm"), ParameterType.QueryString);
@@ -509,13 +510,15 @@ namespace QuantConnect.Brokerages.Tradier
/// <summary>
/// Get full daily, weekly or monthly bars of historical periods:
/// </summary>
public List<TradierHistoryBar> GetHistoricalData(string symbol,
public List<TradierHistoryBar> GetHistoricalData(Symbol symbol,
DateTime start,
DateTime end,
TradierHistoricalDataIntervals interval = TradierHistoricalDataIntervals.Daily)
{
// Create and send request
var ticker = _symbolMapper.GetBrokerageSymbol(symbol);
var request = new RestRequest("markets/history", Method.GET);
request.AddParameter("symbol", symbol, ParameterType.QueryString);
request.AddParameter("symbol", ticker, ParameterType.QueryString);
request.AddParameter("start", start.ToStringInvariant("yyyy-MM-dd"), ParameterType.QueryString);
request.AddParameter("end", end.ToStringInvariant("yyyy-MM-dd"), ParameterType.QueryString);
request.AddParameter("interval", GetEnumDescription(interval));

View File

@@ -13,14 +13,14 @@
* limitations under the License.
*/
using QuantConnect.Logging;
using QuantConnect.Util;
using System;
using System.IO;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using QuantConnect.Logging;
using QuantConnect.Util;
namespace QuantConnect.Brokerages
{
@@ -32,6 +32,7 @@ namespace QuantConnect.Brokerages
private const int ReceiveBufferSize = 8192;
private string _url;
private string _sessionToken;
private CancellationTokenSource _cts;
private ClientWebSocket _client;
private Task _taskConnect;
@@ -40,10 +41,12 @@ namespace QuantConnect.Brokerages
/// <summary>
/// Wraps constructor
/// </summary>
/// <param name="url"></param>
public void Initialize(string url)
/// <param name="url">The target websocket url</param>
/// <param name="sessionToken">The websocket session token</param>
public void Initialize(string url, string sessionToken = null)
{
_url = url;
_sessionToken = sessionToken;
}
/// <summary>
@@ -209,10 +212,14 @@ namespace QuantConnect.Brokerages
{
try
{
lock(_locker)
lock (_locker)
{
_client.DisposeSafely();
_client = new ClientWebSocket();
if (_sessionToken != null)
{
_client.Options.SetRequestHeader("x-session-token", _sessionToken);
}
_client.ConnectAsync(new Uri(_url), connectionCts.Token).SynchronouslyAwaitTask();
}
OnOpen();
@@ -280,12 +287,12 @@ namespace QuantConnect.Brokerages
{
return new TextMessage
{
Message = Encoding.UTF8.GetString(ms.GetBuffer(), 0 , (int)ms.Length),
Message = Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length),
};
}
else if (result.MessageType == WebSocketMessageType.Close)
{
Log.Trace($"WebSocketClientWrapper.HandleConnection({_url}): WebSocketMessageType.Close - Data: {Encoding.UTF8.GetString(ms.GetBuffer(), 0 , (int)ms.Length)}");
Log.Trace($"WebSocketClientWrapper.HandleConnection({_url}): WebSocketMessageType.Close - Data: {Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length)}");
return null;
}
}

View File

@@ -266,12 +266,8 @@ namespace QuantConnect.Brokerages.Zerodha
.Value;
if (order == null)
{
order = _algorithm.Transactions.GetOrderByBrokerageId(brokerId);
if (order == null)
{
// not our order, nothing else to do here
return;
}
Log.Error($"ZerodhaBrokerage.OnOrderUpdate(): order not found: BrokerId: {brokerId}");
return;
}
if (orderUpdate.Status == "CANCELLED")
@@ -295,7 +291,7 @@ namespace QuantConnect.Brokerages.Zerodha
{
var symbol = _symbolMapper.ConvertZerodhaSymbolToLeanSymbol(orderUpdate.InstrumentToken);
var fillPrice = orderUpdate.AveragePrice;
var fillQuantity = orderUpdate.FilledQuantity;
decimal cumulativeFillQuantity = orderUpdate.FilledQuantity;
var direction = orderUpdate.TransactionType == "SELL" ? OrderDirection.Sell : OrderDirection.Buy;
var updTime = orderUpdate.OrderTimestamp.GetValueOrDefault();
@@ -303,27 +299,32 @@ namespace QuantConnect.Brokerages.Zerodha
var orderFee = security.FeeModel.GetOrderFee(
new OrderFeeParameters(security, order));
if (direction == OrderDirection.Sell)
{
fillQuantity = -1 * fillQuantity;
cumulativeFillQuantity = -1 * cumulativeFillQuantity;
}
var status = OrderStatus.Filled;
if (fillQuantity != order.Quantity)
if (cumulativeFillQuantity != order.Quantity)
{
decimal totalFillQuantity;
_fills.TryGetValue(order.Id, out totalFillQuantity);
totalFillQuantity += fillQuantity;
_fills[order.Id] = totalFillQuantity;
status = totalFillQuantity == order.Quantity
? OrderStatus.Filled
: OrderStatus.PartiallyFilled;
status = OrderStatus.PartiallyFilled;
}
decimal totalRegisteredFillQuantity;
_fills.TryGetValue(order.Id, out totalRegisteredFillQuantity);
//async events received from zerodha: https://kite.trade/forum/discussion/comment/34752/#Comment_34752
if (Math.Abs(cumulativeFillQuantity) <= Math.Abs(totalRegisteredFillQuantity))
{
// already filled more quantity
return;
}
_fills[order.Id] = cumulativeFillQuantity;
var fillQuantityInThisEvewnt = cumulativeFillQuantity - totalRegisteredFillQuantity;
var orderEvent = new OrderEvent
(
order.Id, symbol, updTime, status,
direction, fillPrice, fillQuantity,
direction, fillPrice, fillQuantityInThisEvewnt,
orderFee, $"Zerodha Order Event {direction}"
);
@@ -417,7 +418,7 @@ namespace QuantConnect.Brokerages.Zerodha
var security = _securityProvider.GetSecurity(order.Symbol);
var orderFee = security.FeeModel.GetOrderFee(
new OrderFeeParameters(security, order));
var orderProperties = order.Properties as ZerodhaOrderProperties;
var orderProperties = order.Properties as IndiaOrderProperties;
var zerodhaProductType = _zerodhaProductType;
if (orderProperties == null || orderProperties.Exchange == null)
{
@@ -436,7 +437,7 @@ namespace QuantConnect.Brokerages.Zerodha
}
try
{
orderResponse = _kite.PlaceOrder(orderProperties.Exchange.ToUpperInvariant(), order.Symbol.ID.Symbol, order.Direction.ToString().ToUpperInvariant(),
orderResponse = _kite.PlaceOrder(orderProperties.Exchange.ToString(), order.Symbol.ID.Symbol, order.Direction.ToString().ToUpperInvariant(),
orderQuantity, orderPrice, zerodhaProductType, kiteOrderType, null, null, triggerPrice);
}
catch (Exception ex)
@@ -572,7 +573,7 @@ namespace QuantConnect.Brokerages.Zerodha
return;
}
var orderProperties = order.Properties as ZerodhaOrderProperties;
var orderProperties = order.Properties as IndiaOrderProperties;
var zerodhaProductType = _zerodhaProductType;
if (orderProperties == null || orderProperties.Exchange == null)
{
@@ -600,7 +601,7 @@ namespace QuantConnect.Brokerages.Zerodha
{
orderResponse = _kite.ModifyOrder(order.BrokerId[0].ToStringInvariant(),
null,
orderProperties.Exchange.ToUpperInvariant(),
orderProperties.Exchange.ToString(),
order.Symbol.ID.Symbol,
order.Direction.ToString().ToUpperInvariant(),
orderQuantity,

View File

@@ -53,6 +53,7 @@ from QuantConnect.Lean.Engine import *
from QuantConnect.Orders.Fills import *
from QuantConnect.Configuration import *
from QuantConnect.Notifications import *
from QuantConnect.Data.Auxiliary import *
from QuantConnect.Data.Shortable import *
from QuantConnect.Orders.Slippage import *
from QuantConnect.Securities.Forex import *

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -81,6 +81,11 @@ namespace QuantConnect.Brokerages
/// </summary>
Zerodha,
/// <summary>
/// Transaction and submit/execution rules will use Samco models
/// </summary>
Samco,
/// <summary>
/// Transaction and submit/execution rules will use atreyu models
/// </summary>
@@ -89,6 +94,11 @@ namespace QuantConnect.Brokerages
/// <summary>
/// Transaction and submit/execution rules will use TradingTechnologies models
/// </summary>
TradingTechnologies
TradingTechnologies,
/// <summary>
/// Transaction and submit/execution rules will use Kraken models
/// </summary>
Kraken
}
}

View File

@@ -221,6 +221,12 @@ namespace QuantConnect.Brokerages
case BrokerageName.TradingTechnologies:
return new TradingTechnologiesBrokerageModel(accountType);
case BrokerageName.Samco:
return new SamcoBrokerageModel(accountType);
case BrokerageName.Kraken:
return new KrakenBrokerageModel(accountType);
default:
throw new ArgumentOutOfRangeException(nameof(brokerage), brokerage, null);

View File

@@ -0,0 +1,197 @@
/*
* 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 System.Linq;
using QuantConnect.Benchmarks;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Securities;
using QuantConnect.Util;
namespace QuantConnect.Brokerages
{
/// <summary>
/// Kraken Brokerage model
/// </summary>
public class KrakenBrokerageModel : DefaultBrokerageModel
{
private readonly List<string> _fiatsAvailableMargin = new() {"USD", "EUR"};
private readonly List<string> _onlyFiatsAvailableMargin = new() {"BTC", "USDT", "USDC"};
private readonly List<string> _ethAvailableMargin = new() {"REP", "XTZ", "ADA", "EOS", "TRX", "LINK" };
/// <summary>
/// Gets a map of the default markets to be used for each security type
/// </summary>
public override IReadOnlyDictionary<SecurityType, string> DefaultMarkets { get; } = GetDefaultMarkets();
/// <summary>
/// Leverage map of different coins
/// </summary>
public IReadOnlyDictionary<string, decimal> CoinLeverage { get; } = new Dictionary<string, decimal>
{
{"BTC", 5}, // only with fiats
{"ETH", 5},
{"USDT", 2}, // only with fiats
{"XMR", 2},
{"REP", 2}, // eth available
{"XRP", 3},
{"BCH", 2},
{"XTZ", 2}, // eth available
{"LTC", 3},
{"ADA", 3}, // eth available
{"EOS", 3}, // eth available
{"DASH", 3},
{"TRX", 3}, // eth available
{"LINK", 3}, // eth available
{"USDC", 3}, // only with fiats
};
/// <summary>
/// Constructor for Kraken brokerage model
/// </summary>
/// <param name="accountType">Cash or Margin</param>
public KrakenBrokerageModel(AccountType accountType = AccountType.Cash) : base(accountType)
{
}
/// <summary>
/// Returns true if the brokerage could accept this order. This takes into account
/// order type, security type, and order size limits.
/// </summary>
/// <remarks>
/// For example, a brokerage may have no connectivity at certain times, or an order rate/size limit
/// </remarks>
/// <param name="security"></param>
/// <param name="order">The order to be processed</param>
/// <param name="message">If this function returns false, a brokerage message detailing why the order may not be submitted</param>
/// <returns>True if the brokerage could process the order, false otherwise</returns>
public override bool CanSubmitOrder(Security security, Order order, out BrokerageMessageEvent message)
{
message = null;
if (security.Type != SecurityType.Crypto)
{
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported",
StringExtensions.Invariant($"The {nameof(KrakenBrokerageModel)} does not support {security.Type} security type.")
);
return false;
}
return base.CanSubmitOrder(security, order, out message);
}
/// <summary>
/// Kraken does no support update of orders
/// </summary>
/// <param name="security">Security</param>
/// <param name="order">Order that should be updated</param>
/// <param name="request">Update request</param>
/// <param name="message">Outgoing message</param>
/// <returns>Always false as Kraken does no support update of orders</returns>
public override bool CanUpdateOrder(Security security, Order order, UpdateOrderRequest request, out BrokerageMessageEvent message)
{
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, 0, "Brokerage does not support update. You must cancel and re-create instead."); ;
return false;
}
/// <summary>
/// Provides Kraken fee model
/// </summary>
/// <param name="security">Security</param>
/// <returns>Kraken fee model</returns>
public override IFeeModel GetFeeModel(Security security)
{
return new KrakenFeeModel();
}
/// <summary>
/// Gets a new buying power model for the security, returning the default model with the security's configured leverage.
/// For cash accounts, leverage = 1 is used.
/// For margin trading, max leverage = 5
/// </summary>
/// <param name="security">The security to get a buying power model for</param>
/// <returns>The buying power model for this brokerage/security</returns>
public override IBuyingPowerModel GetBuyingPowerModel(Security security)
{
if (AccountType == AccountType.Margin)
{
return new SecurityMarginModel(GetLeverage(security));
}
return new CashBuyingPowerModel();
}
/// <summary>
/// Kraken global leverage rule
/// </summary>
/// <param name="security"></param>
/// <returns></returns>
public override decimal GetLeverage(Security security)
{
if (AccountType == AccountType.Cash)
{
return 1m;
}
// first check whether this security support margin only with fiats.
foreach (var coin in _onlyFiatsAvailableMargin.Where(coin => security.Symbol.ID.Symbol.StartsWith(coin)).Where(coin => _fiatsAvailableMargin.Any(rightFiat => security.Symbol.Value.EndsWith(rightFiat))))
{
return CoinLeverage[coin];
}
List<string> extendedCoinArray = new() {"BTC", "ETH"};
extendedCoinArray.AddRange(_fiatsAvailableMargin);
// Then check whether this security support margin with ETH.
foreach (var coin in _ethAvailableMargin.Where(coin => security.Symbol.ID.Symbol.StartsWith(coin)).Where(coin => extendedCoinArray.Any(rightFiat => security.Symbol.Value.EndsWith(rightFiat))))
{
return CoinLeverage[coin];
}
extendedCoinArray.Remove("ETH");
// At the end check all others.
foreach (var coin in CoinLeverage.Keys.Where(coin => security.Symbol.ID.Symbol.StartsWith(coin)).Where(coin => extendedCoinArray.Any(rightFiat => security.Symbol.Value.EndsWith(rightFiat))))
{
return CoinLeverage[coin];
}
return 1m;
}
/// <summary>
/// Get the benchmark for this model
/// </summary>
/// <param name="securities">SecurityService to create the security with if needed</param>
/// <returns>The benchmark for this brokerage</returns>
public override IBenchmark GetBenchmark(SecurityManager securities)
{
var symbol = Symbol.Create("BTCUSD", SecurityType.Crypto, Market.Kraken);
return SecurityBenchmark.CreateInstance(securities, symbol);
}
/// <summary>
/// Get default markets and specify Kraken as crypto market
/// </summary>
/// <returns>default markets</returns>
private static IReadOnlyDictionary<SecurityType, string> GetDefaultMarkets()
{
var map = DefaultMarketMap.ToDictionary();
map[SecurityType.Crypto] = Market.Kraken;
return map.ToReadOnlyDictionary();
}
}
}

View File

@@ -0,0 +1,208 @@
/*
* 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.Benchmarks;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Orders.TimeInForces;
using QuantConnect.Securities;
using QuantConnect.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using static QuantConnect.StringExtensions;
namespace QuantConnect.Brokerages
{
/// <summary>
/// Brokerage Model implementation for Samco
/// </summary>
public class SamcoBrokerageModel : DefaultBrokerageModel
{
private readonly Type[] _supportedTimeInForces =
{
typeof(GoodTilCanceledTimeInForce),
typeof(DayTimeInForce),
typeof(GoodTilDateTimeInForce)
};
private const decimal _maxLeverage = 7m;
/// <summary>
/// Initializes a new instance of the <see cref="SamcoBrokerageModel"/> class
/// </summary>
/// <param name="accountType">The type of account to be modelled, defaults to <see cref="AccountType.Margin"/></param>
public SamcoBrokerageModel(AccountType accountType = AccountType.Margin) : base(accountType)
{
}
/// <summary>
/// Returns true if the brokerage would be able to execute this order at this time assuming
/// market prices are sufficient for the fill to take place. This is used to emulate the
/// brokerage fills in backtesting and paper trading. For example some brokerages may not
/// perform executions during extended market hours. This is not intended to be checking
/// whether or not the exchange is open, that is handled in the Security.Exchange property.
/// </summary>
/// <param name="security"></param>
/// <param name="order">The order to test for execution</param>
/// <returns>True if the brokerage would be able to perform the execution, false otherwise</returns>
public override bool CanExecuteOrder(Security security, Order order)
{
// validate security type
if (security.Type != SecurityType.Equity &&
security.Type != SecurityType.Option &&
security.Type != SecurityType.Future)
{
return false;
}
// validate time in force
if (!_supportedTimeInForces.Contains(order.TimeInForce.GetType()))
{
return false;
}
return true;
}
/// <summary>
/// Returns true if the brokerage could accept this order. This takes into account order
/// type, security type, and order size limits.
/// </summary>
/// <remarks>
/// For example, a brokerage may have no connectivity at certain times, or an order
/// rate/size limit
/// </remarks>
/// <param name="security">The security being ordered</param>
/// <param name="order">The order to be processed</param>
/// <param name="message">
/// If this function returns false, a brokerage message detailing why the order may not be submitted
/// </param>
/// <returns>True if the brokerage could process the order, false otherwise</returns>
public override bool CanSubmitOrder(Security security, Order order, out BrokerageMessageEvent message)
{
message = null;
// validate security type
if (security.Type != SecurityType.Equity &&
security.Type != SecurityType.Option &&
security.Type != SecurityType.Future)
{
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported",
Invariant($"The {nameof(SamcoBrokerageModel)} does not support {security.Type} security type.")
);
return false;
}
// validate time in force
if (!_supportedTimeInForces.Contains(order.TimeInForce.GetType()))
{
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported",
Invariant($"The {nameof(SamcoBrokerageModel)} does not support {order.TimeInForce.GetType().Name} time in force.")
);
return false;
}
return true;
}
/// <summary>
/// Returns true if the brokerage would allow updating the order as specified by the request
/// </summary>
/// <param name="security">The security of the order</param>
/// <param name="order">The order to be updated</param>
/// <param name="request">The requested update to be made to the order</param>
/// <param name="message">
/// If this function returns false, a brokerage message detailing why the order may not be updated
/// </param>
/// <returns>True if the brokerage would allow updating the order, false otherwise</returns>
public override bool CanUpdateOrder(Security security, Order order, UpdateOrderRequest request, out BrokerageMessageEvent message)
{
message = null;
return true;
}
/// <summary>
/// Gets a map of the default markets to be used for each security type
/// </summary>
public override IReadOnlyDictionary<SecurityType, string> DefaultMarkets { get; } = GetDefaultMarkets();
/// <summary>
/// Gets a new buying power model for the security, returning the default model with the
/// security's configured leverage. For cash accounts, leverage = 1 is used. For margin
/// trading, max leverage = 7
/// </summary>
/// <param name="security">The security to get a buying power model for</param>
/// <returns>The buying power model for this brokerage/security</returns>
public override IBuyingPowerModel GetBuyingPowerModel(Security security)
{
return AccountType == AccountType.Cash
? (IBuyingPowerModel)new CashBuyingPowerModel()
: new SecurityMarginModel(_maxLeverage);
}
/// <summary>
/// Samco global leverage rule
/// </summary>
/// <param name="security"></param>
/// <returns></returns>
public override decimal GetLeverage(Security security)
{
if (AccountType == AccountType.Cash || security.IsInternalFeed() || security.Type == SecurityType.Base)
{
return 1m;
}
if (security.Type == SecurityType.Equity || security.Type == SecurityType.Future || security.Type == SecurityType.Option)
{
return _maxLeverage;
}
throw new ArgumentException($"Invalid security type: {security.Type}", nameof(security));
}
/// <summary>
/// Get the benchmark for this model
/// </summary>
/// <param name="securities">SecurityService to create the security with if needed</param>
/// <returns>The benchmark for this brokerage</returns>
public override IBenchmark GetBenchmark(SecurityManager securities)
{
var symbol = Symbol.Create("NIFTYBEES", SecurityType.Equity, Market.India);
return SecurityBenchmark.CreateInstance(securities, symbol);
}
/// <summary>
/// Provides Samco fee model
/// </summary>
/// <param name="security"></param>
/// <returns></returns>
public override IFeeModel GetFeeModel(Security security)
{
return new SamcoFeeModel();
}
private static IReadOnlyDictionary<SecurityType, string> GetDefaultMarkets()
{
var map = DefaultMarketMap.ToDictionary();
map[SecurityType.Equity] = Market.India;
map[SecurityType.Future] = Market.India;
map[SecurityType.Option] = Market.India;
return map.ToReadOnlyDictionary();
}
}
}

View File

@@ -88,7 +88,7 @@ namespace QuantConnect.Data.Auxiliary
{
FactorFile factorFile = null;
var path = Path.Combine(Globals.DataFolder, "equity", market, "factor_files", permtick.ToLowerInvariant() + ".csv");
var path = Path.Combine(Globals.CacheDataFolder, "equity", market, "factor_files", permtick.ToLowerInvariant() + ".csv");
var factorFileStream = _dataProvider.Fetch(path);
if (factorFileStream != null)

View File

@@ -26,7 +26,7 @@ namespace QuantConnect.Data.Auxiliary
public class MapFilePrimaryExchangeProvider : IPrimaryExchangeProvider
{
private readonly IMapFileProvider _mapFileProvider;
private readonly ConcurrentDictionary<SecurityIdentifier, PrimaryExchange> _primaryExchangeBySid;
private readonly ConcurrentDictionary<SecurityIdentifier, Exchange> _primaryExchangeBySid;
/// <summary>
/// Constructor for Primary Exchange Provider from MapFiles
@@ -35,7 +35,7 @@ namespace QuantConnect.Data.Auxiliary
public MapFilePrimaryExchangeProvider(IMapFileProvider mapFileProvider)
{
_mapFileProvider = mapFileProvider;
_primaryExchangeBySid = new ConcurrentDictionary<SecurityIdentifier, PrimaryExchange>();
_primaryExchangeBySid = new ConcurrentDictionary<SecurityIdentifier, Exchange>();
}
/// <summary>
@@ -43,9 +43,9 @@ namespace QuantConnect.Data.Auxiliary
/// </summary>
/// <param name="securityIdentifier">The security identifier to get the primary exchange for</param>
/// <returns>Returns the primary exchange or null if not found</returns>
public PrimaryExchange GetPrimaryExchange(SecurityIdentifier securityIdentifier)
public Exchange GetPrimaryExchange(SecurityIdentifier securityIdentifier)
{
PrimaryExchange primaryExchange;
Exchange primaryExchange;
if (!_primaryExchangeBySid.TryGetValue(securityIdentifier, out primaryExchange))
{
var mapFile = _mapFileProvider.Get(securityIdentifier.Market).ResolveMapFile(securityIdentifier.Symbol, securityIdentifier.Date);

View File

@@ -40,7 +40,7 @@ namespace QuantConnect.Data.Auxiliary
/// <summary>
/// Gets the mapped symbol
/// </summary>
public PrimaryExchange PrimaryExchange { get; }
public Exchange PrimaryExchange { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MapFileRow"/> class.
@@ -52,7 +52,7 @@ namespace QuantConnect.Data.Auxiliary
/// <summary>
/// Initializes a new instance of the <see cref="MapFileRow"/> class.
/// </summary>
public MapFileRow(DateTime date, string mappedSymbol, PrimaryExchange primaryExchange)
public MapFileRow(DateTime date, string mappedSymbol, Exchange primaryExchange)
{
Date = date;
MappedSymbol = mappedSymbol.LazyToUpper();
@@ -84,7 +84,7 @@ namespace QuantConnect.Data.Auxiliary
public static MapFileRow Parse(string line)
{
var csv = line.Split(',');
var primaryExchange = PrimaryExchange.UNKNOWN;
var primaryExchange = Exchange.UNKNOWN;
if (csv.Length == 3)
{
primaryExchange = Exchanges.GetPrimaryExchange(Convert.ToChar(csv[2], CultureInfo.InvariantCulture));
@@ -166,7 +166,7 @@ namespace QuantConnect.Data.Auxiliary
/// </summary>
public string ToCsv()
{
var encodedExchange = PrimaryExchange == PrimaryExchange.UNKNOWN? string.Empty : $",{Convert.ToChar((byte) PrimaryExchange)}";
var encodedExchange = PrimaryExchange == Exchange.UNKNOWN? string.Empty : $",{Convert.ToChar((byte) PrimaryExchange)}";
return $"{Date.ToStringInvariant(DateFormat.EightCharacter)},{MappedSymbol.ToLowerInvariant()}{encodedExchange}";
}
@@ -176,8 +176,8 @@ namespace QuantConnect.Data.Auxiliary
/// <returns>resulting string</returns>
public override string ToString()
{
var mainExchange = PrimaryExchange == PrimaryExchange.UNKNOWN ? string.Empty : $" - {PrimaryExchange.ToString()}";
var mainExchange = PrimaryExchange == Exchange.UNKNOWN ? string.Empty : $" - {PrimaryExchange.ToString()}";
return Date.ToShortDateString() + ": " + MappedSymbol + mainExchange;
}
}
}
}

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