Merge branch 'master' into price_gap_alpha

This commit is contained in:
Jared
2019-03-12 10:37:49 -07:00
committed by GitHub
184 changed files with 5972 additions and 2213 deletions
@@ -64,9 +64,13 @@ class ForexCalendarAlgorithm(QCAlgorithmFramework):
# Set to use our FxCalendar Alpha Model
self.SetAlpha(FxCalendarTrigger())
# Default Models For Other Framework Settings
# Equally weigh securities in portfolio, based on insights
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
# Set Immediate Execution Model
self.SetExecution(ImmediateExecutionModel())
# Set Null Risk Management Model
self.SetRiskManagement(NullRiskManagementModel())
class FxCalendarTrigger(AlphaModel):
@@ -0,0 +1,239 @@
# 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.
'''
Energy prices, especially Oil and Natural Gas, are in general fairly correlated,
meaning they typically move in the same direction as an overall trend. This Alpha
uses this idea and implements an Alpha Model that takes Natural Gas ETF price
movements as a leading indicator for Crude Oil ETF price movements. We take the
Natural Gas/Crude Oil ETF pair with the highest historical price correlation and
then create insights for Crude Oil depending on whether or not the Natural Gas ETF price change
is above/below a certain threshold that we set (arbitrarily).
This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open
sourced so the community and client funds can see an example of an alpha.
'''
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Orders import OrderStatus
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Risk import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from QuantConnect.Algorithm.Framework.Selection import *
import pandas as pd
from datetime import timedelta
class GasAndCrudeOilEnergyCorrelationAlpha(QCAlgorithmFramework):
def Initialize(self):
self.SetStartDate(2018, 1, 1) #Set Start Date
self.SetCash(100000) #Set Strategy Cash
natural_gas = [Symbol.Create(x, SecurityType.Equity, Market.USA) for x in ['UNG','BOIL','FCG']]
crude_oil = [Symbol.Create(x, SecurityType.Equity, Market.USA) for x in ['USO','UCO','DBO']]
## Set Universe Selection
self.UniverseSettings.Resolution = Resolution.Minute
self.SetUniverseSelection( ManualUniverseSelectionModel(natural_gas + crude_oil) )
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))
## Custom Alpha Model
self.SetAlpha(PairsAlphaModel(leading = natural_gas, following = crude_oil, history_days = 90, resolution = Resolution.Minute))
## Equal-weight our positions, in this case 100% in USO
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(resolution = Resolution.Minute))
## Immediate Execution Fill Model
self.SetExecution(CustomExecutionModel())
## Null Risk-Management Model
self.SetRiskManagement(NullRiskManagementModel())
def OnOrderEvent(self, orderEvent):
if orderEvent.Status == OrderStatus.Filled:
self.Debug(f'Purchased Stock: {orderEvent.Symbol}')
def OnEndOfAlgorithm(self):
for kvp in self.Portfolio:
if kvp.Value.Invested:
self.Log(f'Invested in: {kvp.Key}')
class PairsAlphaModel:
'''This Alpha model assumes that the ETF for natural gas is a good leading-indicator
of the price of the crude oil ETF. The model will take in arguments for a threshold
at which the model triggers an insight, the length of the look-back period for evaluating
rate-of-change of UNG prices, and the duration of the insight'''
def __init__(self, *args, **kwargs):
self.leading = kwargs.get('leading', [])
self.following = kwargs.get('following', [])
self.history_days = kwargs.get('history_days', 90) ## In days
self.lookback = kwargs.get('lookback', 5)
self.resolution = kwargs.get('resolution', Resolution.Hour)
self.prediction_interval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), 5) ## Arbitrary
self.difference_trigger = kwargs.get('difference_trigger', 0.75)
self.symbolDataBySymbol = {}
self.next_update = None
def Update(self, algorithm, data):
if (self.next_update is None) or (algorithm.Time > self.next_update):
self.CorrelationPairsSelection()
self.next_update = algorithm.Time + timedelta(30)
magnitude = round(self.pairs[0].Return / 100, 6)
## Check if Natural Gas returns are greater than the threshold we've set
if self.pairs[0].Return > self.difference_trigger:
return [Insight.Price(self.pairs[1].Symbol, self.prediction_interval, InsightDirection.Up, magnitude)]
if self.pairs[0].Return < -self.difference_trigger:
return [Insight.Price(self.pairs[1].Symbol, self.prediction_interval, InsightDirection.Down, magnitude)]
return []
def CorrelationPairsSelection(self):
## Get returns for each natural gas/oil ETF
daily_return = {}
for symbol, symbolData in self.symbolDataBySymbol.items():
daily_return[symbol] = symbolData.DailyReturnArray
## Estimate coefficients of different correlation measures
tau = pd.DataFrame.from_dict(daily_return).corr(method='kendall')
## Calculate the pair with highest historical correlation
max_corr = -1
for x in self.leading:
df = tau[[x]].loc[self.following]
corr = float(df.max())
if corr > max_corr:
self.pairs = (
self.symbolDataBySymbol[x],
self.symbolDataBySymbol[df.idxmax()[0]])
max_corr = corr
def OnSecuritiesChanged(self, algorithm, changes):
'''Event fired each time the we add/remove securities from the data feed
Args:
algorithm: The algorithm instance that experienced the change in securities
changes: The security additions and removals from the algorithm'''
for removed in changes.RemovedSecurities:
symbolData = self.symbolDataBySymbol.pop(removed.Symbol, None)
if symbolData is not None:
symbolData.RemoveConsolidators(algorithm)
# initialize data for added securities
symbols = [ x.Symbol for x in changes.AddedSecurities ]
history = algorithm.History(symbols, self.history_days + 1, Resolution.Daily)
if history.empty: return
tickers = history.index.levels[0]
for ticker in tickers:
symbol = SymbolCache.GetSymbol(ticker)
if symbol not in self.symbolDataBySymbol:
symbolData = SymbolData(symbol, self.history_days, self.lookback, self.resolution, algorithm)
self.symbolDataBySymbol[symbol] = symbolData
symbolData.UpdateDailyRateOfChange(history.loc[ticker])
history = algorithm.History(symbols, self.lookback, self.resolution)
if history.empty: return
for ticker in tickers:
symbol = SymbolCache.GetSymbol(ticker)
if symbol in self.symbolDataBySymbol:
self.symbolDataBySymbol[symbol].UpdateRateOfChange(history.loc[ticker])
class SymbolData:
'''Contains data specific to a symbol required by this model'''
def __init__(self, symbol, dailyLookback, lookback, resolution, algorithm):
self.Symbol = symbol
self.dailyReturn = RateOfChangePercent('f{symbol}.DailyROCP({1})', 1)
self.dailyConsolidator = algorithm.ResolveConsolidator(symbol, Resolution.Daily)
self.dailyReturnHistory = RollingWindow[IndicatorDataPoint](dailyLookback)
def updatedailyReturnHistory(s, e):
self.dailyReturnHistory.Add(e)
self.dailyReturn.Updated += updatedailyReturnHistory
algorithm.RegisterIndicator(symbol, self.dailyReturn, self.dailyConsolidator)
self.rocp = RateOfChangePercent(f'{symbol}.ROCP({lookback})', lookback)
self.consolidator = algorithm.ResolveConsolidator(symbol, resolution)
algorithm.RegisterIndicator(symbol, self.rocp, self.consolidator)
def RemoveConsolidators(self, algorithm):
algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.consolidator)
algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.dailyConsolidator)
def UpdateRateOfChange(self, history):
for tuple in history.itertuples():
self.rocp.Update(tuple.Index, tuple.close)
def UpdateDailyRateOfChange(self, history):
for tuple in history.itertuples():
self.dailyReturn.Update(tuple.Index, tuple.close)
@property
def Return(self):
return float(self.rocp.Current.Value)
@property
def DailyReturnArray(self):
return pd.Series({x.EndTime: x.Value for x in self.dailyReturnHistory})
def __repr__(self):
return f"{self.rocp.Name} - {Return}"
class CustomExecutionModel(ExecutionModel):
'''Provides an implementation of IExecutionModel that immediately submits market orders to achieve the desired portfolio targets'''
def __init__(self):
'''Initializes a new instance of the ImmediateExecutionModel class'''
self.targetsCollection = PortfolioTargetCollection()
self.previous_symbol = None
def Execute(self, algorithm, targets):
'''Immediately submits orders for the specified portfolio targets.
Args:
algorithm: The algorithm instance
targets: The portfolio targets to be ordered'''
self.targetsCollection.AddRange(targets)
for target in self.targetsCollection.OrderByMarginImpact(algorithm):
open_quantity = sum([x.Quantity for x in algorithm.Transactions.GetOpenOrders(target.Symbol)])
existing = algorithm.Securities[target.Symbol].Holdings.Quantity + open_quantity
quantity = target.Quantity - existing
## Liquidate positions in Crude Oil ETF that is no longer part of the highest-correlation pair
if (str(target.Symbol) != str(self.previous_symbol)) and (self.previous_symbol is not None):
algorithm.Liquidate(self.previous_symbol)
if quantity != 0:
algorithm.MarketOrder(target.Symbol, quantity)
self.previous_symbol = target.Symbol
self.targetsCollection.ClearFulfilled(algorithm)
@@ -15,19 +15,18 @@ from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Python import PythonQuandl
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Indicators import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm.Framework import QCAlgorithmFramework
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel
from QuantConnect.Algorithm.Framework.Selection import ManualUniverseSelectionModel
#
#
# Equity indices exhibit mean reversion in daily returns. The Internal Bar Strength indicator (IBS),
# which relates the closing price of a security to its daily range can be used to identify overbought
# and oversold securities.
@@ -38,90 +37,88 @@ from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelec
#
# Source: Kakushadze, Zura, and Juan Andrés Serur. “4. Exchange-Traded Funds (ETFs).” 151 Trading Strategies, Palgrave Macmillan, 2018, pp. 9091.
#
# <br><br>This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
# You can read the source code for this alpha on Github in <a href="https://github.com/QuantConnect/Lean/blob/master/Algorithm.CSharp/Alphas/GlobalEquityMeanReversionIBSAlpha.cs">C#</a>
# or <a href="https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/Alphas/GlobalEquityMeanReversionIBSAlpha.py">Python</a>.
#
# This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
#
class GlobalEquityMeanReversionIBSAlphaAlgorithm(QCAlgorithmFramework):
class GlobalEquityMeanReversionIBSAlpha(QCAlgorithmFramework):
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetCash(100000)
# Set zero transaction fees
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))
# Global Equity ETF tickers
tickers = ["ECH","EEM","EFA","EPHE","EPP","EWA","EWC","EWG",
"EWH","EWI","EWJ","EWL","EWM","EWM","EWO","EWP",
"EWQ","EWS","EWT","EWU","EWY","EWZ","EZA","FXI",
"GXG","IDX","ILF","EWM","QQQ","RSX","SPY","THD"]
"GXG","IDX","ILF","EWM","QQQ","RSX","SPY","THD"]
symbols = [Symbol.Create(ticker, SecurityType.Equity, Market.USA) for ticker in tickers]
# Manually curated universe
self.UniverseSettings.Resolution = Resolution.Daily
self.SetUniverseSelection(ManualUniverseSelectionModel(symbols))
# Use GlobalEquityMeanReversionAlphaModel to establish insights
self.SetAlpha(MeanReversionIBSAlphaModel())
# Equally weigh securities in portfolio, based on insights
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
## Set immediate execution
# Set Immediate Execution Model
self.SetExecution(ImmediateExecutionModel())
## Set null risk management
# Set Null Risk Management Model
self.SetRiskManagement(NullRiskManagementModel())
class MeanReversionIBSAlphaModel(AlphaModel):
'''Uses ranking of Internal Bar Strength (IBS) to create direction prediction for insights'''
def __init__(self, *args, **kwargs):
self.lookback = kwargs['lookback'] if 'lookback' in kwargs else 1
lookback = kwargs['lookback'] if 'lookback' in kwargs else 1
resolution = kwargs['resolution'] if 'resolution' in kwargs else Resolution.Daily
self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), lookback)
self.numberOfStocks = kwargs['numberOfStocks'] if 'numberOfStocks' in kwargs else 2
self.resolution = kwargs['resolution'] if 'resolution' in kwargs else Resolution.Daily
self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.lookback)
def Update(self, algorithm, data):
insights = []
symbolsIBS = dict()
returns = dict()
for security in algorithm.ActiveSecurities.Values:
if security.HasData:
high = security.High
low = security.Low
hilo = high - low
# Do not consider symbol with zero open and avoid division by zero
if security.Open * hilo != 0:
# Internal bar strength (IBS)
symbolsIBS[security.Symbol] = (security.Close-low)/hilo
symbolsIBS[security.Symbol] = (security.Close - low)/hilo
returns[security.Symbol] = security.Close/security.Open-1
# Number of stocks cannot be higher than half of symbolsIBS length
number_of_stocks = min(int(len(symbolsIBS)/2), self.numberOfStocks)
if number_of_stocks == 0:
return []
# Rank and retrieve the securities with the highest IBS value
highIBS = dict(sorted(symbolsIBS.items(), key=lambda kv: kv[1],reverse=True)[0:number_of_stocks])
# Rank and retrieve the securities with the lowest IBS value
lowIBS = dict(sorted(symbolsIBS.items(), key=lambda kv: kv[1],reverse=False)[0:number_of_stocks])
# Rank securities with the highest IBS value
ordered = sorted(symbolsIBS.items(), key=lambda kv: (round(kv[1], 6), kv[0]), reverse=True)
highIBS = dict(ordered[0:number_of_stocks]) # Get highest IBS
lowIBS = dict(ordered[-number_of_stocks:]) # Get lowest IBS
# Emit "down" insight for the securities with the highest IBS value
for key,value in highIBS.items():
insights.append(Insight.Price(key, self.predictionInterval, InsightDirection.Down, -returns[key], None))
insights.append(Insight.Price(key, self.predictionInterval, InsightDirection.Down, abs(returns[key]), None))
# Emit "up" insight for the securities with the lowest IBS value
for key,value in lowIBS.items():
insights.append(Insight.Price(key, self.predictionInterval, InsightDirection.Up, -returns[key], None))
insights.append(Insight.Price(key, self.predictionInterval, InsightDirection.Up, abs(returns[key]), None))
return insights
return insights
@@ -0,0 +1,245 @@
# 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 clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Indicators import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
from datetime import timedelta, datetime
from math import ceil
from itertools import chain
#
# This alpha picks stocks according to Joel Greenblatt's Magic Formula.
# First, each stock is ranked depending on the relative value of the ratio EV/EBITDA. For example, a stock
# that has the lowest EV/EBITDA ratio in the security universe receives a score of one while a stock that has
# the tenth lowest EV/EBITDA score would be assigned 10 points.
#
# Then, each stock is ranked and given a score for the second valuation ratio, Return on Capital (ROC).
# Similarly, a stock that has the highest ROC value in the universe gets one score point.
# The stocks that receive the lowest combined score are chosen for insights.
#
# Source: Greenblatt, J. (2010) The Little Book That Beats the Market
#
# This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open
# sourced so the community and client funds can see an example of an alpha.
#
class GreenblattMagicFormulaAlpha(QCAlgorithmFramework):
''' Alpha Streams: Benchmark Alpha: Pick stocks according to Joel Greenblatt's Magic Formula'''
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetCash(100000)
#Set zero transaction fees
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))
# select stocks using MagicFormulaUniverseSelectionModel
self.SetUniverseSelection(GreenBlattMagicFormulaUniverseSelectionModel())
# Use MagicFormulaAlphaModel to establish insights
self.SetAlpha(RateOfChangeAlphaModel())
# Equally weigh securities in portfolio, based on insights
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
## Set Immediate Execution Model
self.SetExecution(ImmediateExecutionModel())
## Set Null Risk Management Model
self.SetRiskManagement(NullRiskManagementModel())
class RateOfChangeAlphaModel(AlphaModel):
'''Uses Rate of Change (ROC) to create magnitude prediction for insights.'''
def __init__(self, *args, **kwargs):
self.lookback = kwargs.get('lookback', 1)
self.resolution = kwargs.get('resolution', Resolution.Daily)
self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.lookback)
self.symbolDataBySymbol = {}
def Update(self, algorithm, data):
insights = []
for symbol, symbolData in self.symbolDataBySymbol.items():
if symbolData.CanEmit:
insights.append(Insight.Price(symbol, self.predictionInterval, InsightDirection.Up, symbolData.Return, None))
return insights
def OnSecuritiesChanged(self, algorithm, changes):
# clean up data for removed securities
for removed in changes.RemovedSecurities:
symbolData = self.symbolDataBySymbol.pop(removed.Symbol, None)
if symbolData is not None:
symbolData.RemoveConsolidators(algorithm)
# initialize data for added securities
symbols = [ x.Symbol for x in changes.AddedSecurities ]
history = algorithm.History(symbols, self.lookback, self.resolution)
if history.empty: return
tickers = history.index.levels[0]
for ticker in tickers:
symbol = SymbolCache.GetSymbol(ticker)
if symbol not in self.symbolDataBySymbol:
symbolData = SymbolData(symbol, self.lookback)
self.symbolDataBySymbol[symbol] = symbolData
symbolData.RegisterIndicators(algorithm, self.resolution)
symbolData.WarmUpIndicators(history.loc[ticker])
class SymbolData:
'''Contains data specific to a symbol required by this model'''
def __init__(self, symbol, lookback):
self.Symbol = symbol
self.ROC = RateOfChange(f'{symbol}.ROC({lookback})', lookback)
self.Consolidator = None
self.previous = 0
def RegisterIndicators(self, algorithm, resolution):
self.Consolidator = algorithm.ResolveConsolidator(self.Symbol, resolution)
algorithm.RegisterIndicator(self.Symbol, self.ROC, self.Consolidator)
def RemoveConsolidators(self, algorithm):
if self.Consolidator is not None:
algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.Consolidator)
def WarmUpIndicators(self, history):
for tuple in history.itertuples():
self.ROC.Update(tuple.Index, tuple.close)
@property
def Return(self):
return float(self.ROC.Current.Value)
@property
def CanEmit(self):
if self.previous == self.ROC.Samples:
return False
self.previous = self.ROC.Samples
return self.ROC.IsReady
def __str__(self, **kwargs):
return '{}: {:.2%}'.format(self.ROC.Name, (1 + self.Return)**252 - 1)
class GreenBlattMagicFormulaUniverseSelectionModel(FundamentalUniverseSelectionModel):
'''Defines a universe according to Joel Greenblatt's Magic Formula, as a universe selection model for the framework algorithm.
From the universe QC500, stocks are ranked using the valuation ratios, Enterprise Value to EBITDA (EV/EBITDA) and Return on Assets (ROA).
'''
def __init__(self,
filterFineData = True,
universeSettings = None,
securityInitializer = None):
'''Initializes a new default instance of the MagicFormulaUniverseSelectionModel'''
super().__init__(filterFineData, universeSettings, securityInitializer)
# Number of stocks in Coarse Universe
self.NumberOfSymbolsCoarse = 500
# Number of sorted stocks in the fine selection subset using the valuation ratio, EV to EBITDA (EV/EBITDA)
self.NumberOfSymbolsFine = 20
# Final number of stocks in security list, after sorted by the valuation ratio, Return on Assets (ROA)
self.NumberOfSymbolsInPortfolio = 10
self.lastMonth = -1
self.dollarVolumeBySymbol = {}
self.symbols = []
def SelectCoarse(self, algorithm, coarse):
'''Performs coarse selection for constituents.
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'''
month = algorithm.Time.month
if month == self.lastMonth:
return self.symbols
self.lastMonth = month
# 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
filtered = [x for x in coarse if x.HasFundamentalData]
# sort the stocks by dollar volume and take the top 1000
top = sorted(filtered, key=lambda x: x.DollarVolume, reverse=True)[:self.NumberOfSymbolsCoarse]
self.dollarVolumeBySymbol = { i.Symbol: i.DollarVolume for i in top }
self.symbols = list(self.dollarVolumeBySymbol.keys())
return self.symbols
def SelectFine(self, algorithm, fine):
'''QC500: Performs fine selection for the coarse selection constituents
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
Magic Formula: Rank stocks by Enterprise Value to EBITDA (EV/EBITDA)
Rank subset of previously ranked stocks (EV/EBITDA), using the valuation ratio Return on Assets (ROA)'''
# QC500:
## 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
filteredFine = [x for x in fine if x.CompanyReference.CountryId == "USA"
and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
and (algorithm.Time - x.SecurityReference.IPODate).days > 180
and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 5e8]
count = len(filteredFine)
if count == 0: return []
myDict = dict()
percent = float(self.NumberOfSymbolsFine / count)
# select stocks with top dollar volume in every single sector
for key in ["N", "M", "U", "T", "B", "I"]:
value = [x for x in filteredFine if x.CompanyReference.IndustryTemplateCode == key]
value = sorted(value, key=lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse = True)
myDict[key] = value[:ceil(len(value) * percent)]
# stocks in QC500 universe
topFine = chain.from_iterable(myDict.values())
# Magic Formula:
## Rank stocks by Enterprise Value to EBITDA (EV/EBITDA)
## Rank subset of previously ranked stocks (EV/EBITDA), using the valuation ratio Return on Assets (ROA)
# sort stocks in the security universe of QC500 based on Enterprise Value to EBITDA valuation ratio
sortedByEVToEBITDA = sorted(topFine, key=lambda x: x.ValuationRatios.EVToEBITDA , reverse=True)
# sort subset of stocks that have been sorted by Enterprise Value to EBITDA, based on the valuation ratio Return on Assets (ROA)
sortedByROA = sorted(sortedByEVToEBITDA[:self.NumberOfSymbolsFine], key=lambda x: x.ValuationRatios.ForwardROA, reverse=False)
# retrieve list of securites in portfolio
self.symbols = [f.Symbol for f in sortedByROA[:self.NumberOfSymbolsInPortfolio]]
return self.symbols
@@ -21,12 +21,14 @@ AddReference("QuantConnect.Indicators")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import QCAlgorithmFrameworkBridge
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Indicators import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Data.Consolidators import *
from datetime import datetime, timedelta
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm.Framework import QCAlgorithmFramework
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Selection import ManualUniverseSelectionModel
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel
from datetime import datetime, timedelta, time
#
# Reversal strategy that goes long when price crosses below SMA and Short when price crosses above SMA.
@@ -36,32 +38,43 @@ from datetime import datetime, timedelta
# http://people.brandeis.edu/~blebaron/wps/fxnyc.pdf
# http://www.fma.org/Reno/Papers/ForeignExchangeReversalsinNewYorkTime.pdf
#
class IntradayReversalCurrencyMarketsFrameworkAlgorithm(QCAlgorithmFramework):
# This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
#
class IntradayReversalCurrencyMarketsAlpha(QCAlgorithmFramework):
def Initialize(self):
self.SetStartDate(2015, 1, 1)
self.SetCash(100000)
# Set zero transaction fees
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))
# Select resolution
resolution = Resolution.Hour
# Reversion on the USD.
symbols = [
Symbol.Create("EURUSD", SecurityType.Forex, Market.Oanda)
]
symbols = [Symbol.Create("EURUSD", SecurityType.Forex, Market.Oanda)]
# Set requested data resolution
self.UniverseSettings.Resolution = resolution
self.SetUniverseSelection(ManualUniverseSelectionModel( symbols ))
self.UniverseSettings.Resolution = resolution
self.SetUniverseSelection(ManualUniverseSelectionModel(symbols))
self.SetAlpha(IntradayReversalAlphaModel(5, resolution))
# Equally weigh securities in portfolio, based on insights
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
# Set Immediate Execution Model
self.SetExecution(ImmediateExecutionModel())
# Set Null Risk Management Model
self.SetRiskManagement(NullRiskManagementModel())
#Set WarmUp for Indicators
self.SetWarmUp(20)
class IntradayReversalAlphaModel(AlphaModel):
'''Alpha model that uses a Price/SMA Crossover to create insights on Hourly Frequency.
Frequency: Hourly data with 5-hour simple moving average.
@@ -75,66 +88,52 @@ class IntradayReversalAlphaModel(AlphaModel):
self.resolution = resolution
self.cache = {} # Cache for SymbolData
self.Name = 'IntradayReversalAlphaModel'
def Update(self, algorithm, data):
# Set the time to close all positions at 3PM
self.timeToClose = datetime(algorithm.Time.year, algorithm.Time.month, algorithm.Time.day, 15, 1, 00, tzinfo = algorithm.Time.tzinfo)
timeToClose = algorithm.Time.replace(hour=15, minute=1, second=0)
insights = []
for security in algorithm.ActiveSecurities.Values:
if self.ShouldEmitInsight(algorithm, security.Symbol):
direction = InsightDirection.Down
if self.cache[security.Symbol].is_uptrend(algorithm.Securities[security.Symbol].Price):
direction = InsightDirection.Up
for kvp in algorithm.ActiveSecurities:
symbol = kvp.Key
if self.ShouldEmitInsight(algorithm, symbol) and symbol in self.cache:
price = kvp.Value.Price
symbolData = self.cache[symbol]
direction = InsightDirection.Up if symbolData.is_uptrend(price) else InsightDirection.Down
# Ignore signal for same direction as previous signal (when no crossover)
if direction == self.cache[security.Symbol].PreviousDirection:
if direction == symbolData.PreviousDirection:
continue
# Update the predictionInterval so insight goes Flat by timeToClose
predictionInterval = self.timeToClose - algorithm.Time
# Generate insight
insight = Insight.Price(security.Symbol, predictionInterval, direction)
# Save the current Insight Direction to check when the crossover happens
self.cache[security.Symbol].PreviousDirection = insight.Direction
insights.append(insight)
symbolData.PreviousDirection = direction
# Generate insight
insights.append(Insight.Price(symbol, timeToClose, direction))
return insights
# Handle creation of the new security and its cache class.
# Simplified in this example as there is 1 asset.
def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.AddedSecurities:
self.cache[security.Symbol] = SymbolData(algorithm, security.Symbol, self.period_sma, self.resolution)
# Time to control when to start and finish emitting (10AM to 3PM)
'''Handle creation of the new security and its cache class.
Simplified in this example as there is 1 asset.'''
for security in changes.AddedSecurities:
self.cache[security.Symbol] = SymbolData(algorithm, security.Symbol, self.period_sma, self.resolution)
def ShouldEmitInsight(self, algorithm, symbol):
current = algorithm.Time
insightTimeStart = datetime(current.year, current.month, current.day, 10, 00, 00, tzinfo = current.tzinfo).time()
insightTimeEnd = datetime(current.year, current.month, current.day, 15, 00, 00, tzinfo = current.tzinfo).time()
currentTime = current.time()
if not algorithm.Securities[symbol].HasData or currentTime < insightTimeStart or currentTime > insightTimeEnd:
return False
else:
return True
'''Time to control when to start and finish emitting (10AM to 3PM)'''
timeOfDay = algorithm.Time.time()
return algorithm.Securities[symbol].HasData and timeOfDay >= time(10) and timeOfDay <= time(15)
class SymbolData:
def __init__(self, algorithm, symbol, period_sma, resolution):
self.PreviousDirection = None
def __init__(self, algorithm, symbol, period_sma, resolution):
self.PreviousDirection = InsightDirection.Flat
self.priceSMA = algorithm.SMA(symbol, period_sma, resolution)
def is_uptrend(self, price):
if self.priceSMA.IsReady:
return price < self.priceSMA.Current.Value * 1.001
else:
return False
def is_uptrend(self, price):
return self.priceSMA.IsReady and price < round(self.priceSMA.Current.Value * 1.001, 6)
@@ -14,17 +14,19 @@
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Indicators import *
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm.Framework import QCAlgorithmFramework
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel
from QuantConnect.Algorithm.Framework.Selection import CoarseFundamentalUniverseSelectionModel
#
# Academic research suggests that stock market participants generally place their orders at the market open and close.
@@ -38,84 +40,99 @@ from QuantConnect.Orders.Fees import ConstantFeeModel
# Source: Lunina, V. (June 2011). The Intraday Dynamics of Stock Returns and Trading Activity: Evidence from OMXS 30 (Master's Essay, Lund University).
# Retrieved from http://lup.lub.lu.se/luur/download?func=downloadFile&recordOId=1973850&fileOId=1973852
#
# This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community
# and client funds can see an example of an alpha.
# This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
#
class MeanReversionLunchBreakAlphaAlgorithm(QCAlgorithmFramework):
class MeanReversionLunchBreakAlpha(QCAlgorithmFramework):
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetCash(100000)
# Set zero transaction fees
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))
# Use Hourly Data For Simplicity
self.UniverseSettings.Resolution = Resolution.Hour
self.SetUniverseSelection(CoarseFundamentalUniverseSelectionModel(self.CoarseSelectionFunction))
# Use MeanReversionLunchBreakAlphaModel to establish insights
self.SetAlpha(MeanReversionLunchBreakAlphaModel())
# Equally weigh securities in portfolio, based on insights
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
## Set immediate execution
# Set Immediate Execution Model
self.SetExecution(ImmediateExecutionModel())
## Set null risk management
self.SetRiskManagement(NullRiskManagementModel())
# Set Null Risk Management Model
self.SetRiskManagement(NullRiskManagementModel())
# Sort the data by daily dollar volume and take the top '20' ETFs
def CoarseSelectionFunction(self, coarse):
sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
filtered = [ x.Symbol for x in sortedByDollarVolume if not x.HasFundamentalData ]
return filtered[:20]
class MeanReversionLunchBreakAlphaModel(AlphaModel):
'''Uses the price return between the close of previous day to 12:00 the day after to
predict mean-reversion of stock price during lunch break and creates direction prediction
for insights accordingly.'''
def __init__(self, *args, **kwargs):
self.lookback = kwargs['lookback'] if 'lookback' in kwargs else 1
lookback = kwargs['lookback'] if 'lookback' in kwargs else 1
self.resolution = Resolution.Hour
self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.lookback)
self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), lookback)
self.symbolDataBySymbol = dict()
def Update(self, algorithm, data):
insights = []
if algorithm.Time.hour != 12:
return []
# Retrieve symbols for active securities that have data
symbols = [x.Key for x in algorithm.ActiveSecurities]
for symbol, symbolData in self.symbolDataBySymbol.items():
if data.Bars.ContainsKey(symbol):
bar = data.Bars.GetValue(symbol)
symbolData.Update(bar.EndTime, bar.Close)
return [] if algorithm.Time.hour != 12 else \
[x.Insight for x in self.symbolDataBySymbol.values()]
def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.RemovedSecurities:
self.symbolDataBySymbol.pop(security.Symbol, None)
# Retrieve price history for all securities in the security universe
hist = algorithm.History(symbols, 4, self.resolution)
# Return 'None' if no history exists
if hist.empty:
algorithm.Log(f"No data on {algorithm.Time}")
return []
# Get close price for securities
hist = hist.close.unstack(level=0)
# and update the indicators in the SymbolData object
symbols = [x.Symbol for x in changes.AddedSecurities]
history = algorithm.History(symbols, 1, self.resolution)
if history.empty:
algorithm.Debug(f"No data on {algorithm.Time}")
return
history = history.close.unstack(level = 0)
# Retrieve the price change from close price the previous day
returns=hist.pct_change(periods=3).tail(1).reset_index(drop=True).to_dict()
# Retrieve the mean value of returns for magnitude prediction
mean=hist.pct_change().mean().to_dict()
for symbol in list(returns):
# Emit "down" insight for the securities that increased in value and
# emit "up" insight for securities that have decreased in value
direction = InsightDirection.Down if returns[symbol][0] > 0 else InsightDirection.Up
insights.append(Insight.Price(symbol, self.predictionInterval, direction, -mean[symbol], None))
return insights
for ticker, values in history.iteritems():
symbol = next((x for x in symbols if str(x) == ticker ), None)
if symbol in self.symbolDataBySymbol or symbol is None: continue
self.symbolDataBySymbol[symbol] = self.SymbolData(symbol, self.predictionInterval)
self.symbolDataBySymbol[symbol].Update(values.index[0], values[0])
class SymbolData:
def __init__(self, symbol, period):
self.symbol = symbol
self.period = period
# Mean value of returns for magnitude prediction
self.meanOfPriceChange = IndicatorExtensions.SMA(RateOfChangePercent(1),3)
# Price change from close price the previous day
self.priceChange = RateOfChangePercent(3)
def Update(self, time, value):
return self.meanOfPriceChange.Update(time, value) and \
self.priceChange.Update(time, value)
@property
def Insight(self):
direction = InsightDirection.Down if self.priceChange.Current.Value > 0 else InsightDirection.Up
margnitude = abs(self.meanOfPriceChange.Current.Value)
return Insight.Price(self.symbol, self.period, direction, margnitude, None)
-131
View File
@@ -1,131 +0,0 @@
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Python import PythonQuandl
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Indicators import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
from itertools import chain
from math import ceil
from datetime import timedelta, datetime
from decimal import Decimal
from collections import deque
import pandas as pd
# Identify "pumped" penny stocks and predict that the price of a "Pumped" penny stock reverts to mean
class PumpAndDumpAlphaAlgorithm(QCAlgorithmFramework):
''' Alpha Streams: Benchmark Alpha: Identify "pumped" penny stocks and predict that the price of a "pumped" penny stock reverts to mean'''
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetCash(100000)
# select stocks using PennyStockUniverseSelectionModel
self.UniverseSettings.Resolution = Resolution.Daily
self.SetUniverseSelection(PennyStockUniverseSelectionModel())
# Use PumpAndDumpAlphaModel to establish insights
self.SetAlpha(PumpAndDumpAlphaModel())
# Equally weigh securities in portfolio, based on insights
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
class PumpAndDumpAlphaModel(AlphaModel):
'''Uses ranking of intraday percentage difference between open price and close price to create magnitude and direction prediction for insights'''
def __init__(self, *args, **kwargs):
self.lookback = kwargs['lookback'] if 'lookback' in kwargs else 1
self.numberOfStocks = kwargs['numberOfStocks'] if 'numberOfStocks' in kwargs else 10
self.resolution = kwargs['resolution'] if 'resolution' in kwargs else Resolution.Daily
self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.lookback)
self.symbolDataBySymbol = {}
def Update(self, algorithm, data):
insights = []
ret = []
symbols = []
activeSecurities = [x.Key for x in algorithm.ActiveSecurities]
for symbol in activeSecurities:
if algorithm.ActiveSecurities[symbol].HasData:
open = algorithm.Securities[symbol].Open
close = algorithm.Securities[symbol].Close
if open != 0:
openCloseReturn = close/open - 1
ret.append(openCloseReturn)
symbols.append(symbol)
# Intraday price change for penny stocks
symbolsRet = dict(zip(symbols,ret))
# Rank penny stocks on one day price change and retrieve list of ten "pumped" penny stocks
pumpedStocks = dict(sorted(symbolsRet.items(), key=lambda kv: kv[1],reverse=True)[0:self.numberOfStocks])
# Emit "down" insight for "pumped" penny stocks
for key,value in pumpedStocks.items():
insights.append(Insight.Price(key, self.predictionInterval, InsightDirection.Down, value, None))
return insights
class PennyStockUniverseSelectionModel(FundamentalUniverseSelectionModel):
'''Defines a universe of penny stocks, as a universe selection model for the framework algorithm.'''
def __init__(self,
filterFineData = True,
universeSettings = None,
securityInitializer = None):
'''Initializes a new default instance of the MagicFormulaUniverseSelectionModel'''
super().__init__(filterFineData, universeSettings, securityInitializer)
# Number of stocks in Coarse and Fine Universe
self.NumberOfSymbolsCoarse = 500
self.lastMonth = -1
self.dollarVolumeBySymbol = {}
self.symbols = []
def SelectCoarse(self, algorithm, coarse):
'''Performs coarse selection for constituents.
The stocks must have fundamental data
The stock must have positive previous-day close price
The stock must have volume between $1000000 and $10000 on the previous trading day
The stock must cost less than $5'''
coarse = list(coarse)
if len(coarse) == 0:
return self.symbols
month = coarse[0].EndTime.month
if month == self.lastMonth:
return self.symbols
self.lastMonth = month
# The stocks must have fundamental data
# The stock must have positive previous-day close price
# The stock must have volume between $1000000 and $10000 on the previous trading day
# The stock must cost less than $5
filtered = [x for x in coarse if x.HasFundamentalData
and 1000000 > x.Volume > 10000
and 5 > x.Price > 0]
# sort the stocks by dollar volume and take the top 500
top = sorted(filtered, key=lambda x: x.DollarVolume, reverse=True)[:self.NumberOfSymbolsCoarse]
self.dollarVolumeBySymbol = { i.Symbol: i.DollarVolume for i in top }
self.symbols = list(self.dollarVolumeBySymbol.keys())
return self.symbols
@@ -55,9 +55,14 @@ class RebalancingLeveragedETFAlpha(QCAlgorithmFramework):
self.SetUniverseSelection(ManualUniverseSelectionModel())
# Select the demonstration alpha model
self.SetAlpha(RebalancingLeveragedETFAlphaModel(groups))
# Select our default model types
# Equally weigh securities in portfolio, based on insights
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
# Set Immediate Execution Model
self.SetExecution(ImmediateExecutionModel())
# Set Null Risk Management Model
self.SetRiskManagement(NullRiskManagementModel())
@@ -0,0 +1,172 @@
# 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 clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Indicators")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Data.Market import TradeBar
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Risk import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from QuantConnect.Algorithm.Framework.Selection import *
from QuantConnect.Indicators import RollingWindow, SimpleMovingAverage
from datetime import timedelta, datetime
import numpy as np
#
# A number of companies publicly trade two different classes of shares
# in US equity markets. If both assets trade with reasonable volume, then
# the underlying driving forces of each should be similar or the same. Given
# this, we can create a relatively dollar-netural long/short portfolio using
# the dual share classes. Theoretically, any deviation of this portfolio from
# its mean-value should be corrected, and so the motivating idea is based on
# mean-reversion. Using a Simple Moving Average indicator, we can
# compare the value of this portfolio against its SMA and generate insights
# to buy the under-valued symbol and sell the over-valued symbol.
#
# This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open
# sourced so the community and client funds can see an example of an alpha.
#
class ShareClassMeanReversionAlgorithm(QCAlgorithmFramework):
def Initialize(self):
self.SetStartDate(2019, 1, 1) #Set Start Date
self.SetCash(100000) #Set Strategy Cash
self.SetWarmUp(20)
## Setup Universe settings and tickers to be used
tickers = ['VIA','VIAB']
self.UniverseSettings.Resolution = Resolution.Minute
symbols = [ Symbol.Create(ticker, SecurityType.Equity, Market.USA) for ticker in tickers]
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0))) ## Set $0 fees to mimic High-Frequency Trading
## Set Manual Universe Selection
self.SetUniverseSelection( ManualUniverseSelectionModel(symbols) )
## Set Custom Alpha Model
self.SetAlpha(ShareClassMeanReversionAlphaModel(tickers = tickers))
## Set Equal Weighting Portfolio Construction Model
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
## Set Immediate Execution Model
self.SetExecution(ImmediateExecutionModel())
## Set Null Risk Management Model
self.SetRiskManagement(NullRiskManagementModel())
class ShareClassMeanReversionAlphaModel(AlphaModel):
''' Initialize helper variables for the algorithm'''
def __init__(self, *args, **kwargs):
self.sma = SimpleMovingAverage(10)
self.position_window = RollingWindow[Decimal](2)
self.alpha = None
self.beta = None
if 'tickers' not in kwargs:
raise Exception('ShareClassMeanReversionAlphaModel: Missing argument: "tickers"')
self.tickers = kwargs['tickers']
self.position_value = None
self.invested = False
self.liquidate = 'liquidate'
self.long_symbol = self.tickers[0]
self.short_symbol = self.tickers[1]
self.resolution = kwargs['resolution'] if 'resolution' in kwargs else Resolution.Minute
self.prediction_interval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), 5) ## Arbitrary
self.insight_magnitude = 0.001
def Update(self, algorithm, data):
insights = []
## Check to see if either ticker will return a NoneBar, and skip the data slice if so
for security in algorithm.Securities:
if self.DataEventOccured(data, security.Key):
return insights
## If Alpha and Beta haven't been calculated yet, then do so
if (self.alpha is None) or (self.beta is None):
self.CalculateAlphaBeta(algorithm, data)
algorithm.Log('Alpha: ' + str(self.alpha))
algorithm.Log('Beta: ' + str(self.beta))
## If the SMA isn't fully warmed up, then perform an update
if not self.sma.IsReady:
self.UpdateIndicators(data)
return insights
## Update indicator and Rolling Window for each data slice passed into Update() method
self.UpdateIndicators(data)
## Check to see if the portfolio is invested. If no, then perform value comparisons and emit insights accordingly
if not self.invested:
if self.position_value >= self.sma.Current.Value:
insights.append(Insight(self.long_symbol, self.prediction_interval, InsightType.Price, InsightDirection.Down, self.insight_magnitude, None))
insights.append(Insight(self.short_symbol, self.prediction_interval, InsightType.Price, InsightDirection.Up, self.insight_magnitude, None))
## Reset invested boolean
self.invested = True
elif self.position_value < self.sma.Current.Value:
insights.append(Insight(self.long_symbol, self.prediction_interval, InsightType.Price, InsightDirection.Up, self.insight_magnitude, None))
insights.append(Insight(self.short_symbol, self.prediction_interval, InsightType.Price, InsightDirection.Down, self.insight_magnitude, None))
## Reset invested boolean
self.invested = True
## If the portfolio is invested and crossed back over the SMA, then emit flat insights
elif self.invested and self.CrossedMean():
## Reset invested boolean
self.invested = False
return Insight.Group(insights)
def DataEventOccured(self, data, symbol):
## Helper function to check to see if data slice will contain a symbol
if data.Splits.ContainsKey(symbol) or \
data.Dividends.ContainsKey(symbol) or \
data.Delistings.ContainsKey(symbol) or \
data.SymbolChangedEvents.ContainsKey(symbol):
return True
def UpdateIndicators(self, data):
## Calculate position value and update the SMA indicator and Rolling Window
self.position_value = (self.alpha * data[self.long_symbol].Close) - (self.beta * data[self.short_symbol].Close)
self.sma.Update(data[self.long_symbol].EndTime, self.position_value)
self.position_window.Add(self.position_value)
def CrossedMean(self):
## Check to see if the position value has crossed the SMA and then return a boolean value
if (self.position_window[0] >= self.sma.Current.Value) and (self.position_window[1] < self.sma.Current.Value):
return True
elif (self.position_window[0] < self.sma.Current.Value) and (self.position_window[1] >= self.sma.Current.Value):
return True
else:
return False
def CalculateAlphaBeta(self, algorithm, data):
## Calculate Alpha and Beta, the initial number of shares for each security needed to achieve a 50/50 weighting
self.alpha = algorithm.CalculateOrderQuantity(self.long_symbol, 0.5)
self.beta = algorithm.CalculateOrderQuantity(self.short_symbol, 0.5)
@@ -1,135 +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.
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.Algorithm import *
from QuantConnect.Algorithm.Framework import QCAlgorithmFrameworkBridge
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Indicators import *
from QuantConnect.Orders.Fees import ConstantFeeModel
import numpy as np
import pandas as pd
from datetime import timedelta, datetime
from decimal import Decimal
class ShareClassMeanReversionAlphaModel(QCAlgorithmFrameworkBridge):
def Initialize(self):
## Set testing timeframe and starting cash
self.SetStartDate(2019,1,1)
self.SetCash(100000)
## We choose a pair of stock tickers that represent different
## share classes of the same company -- the idea being that their
## prices will move almost identically but likely with slight deviations
symbols = ['GOOG','GOOGL']
self.symbols = symbols
for symbol in symbols:
self.AddEquity(symbol, Resolution.Minute)
self.Securities[symbol].FeeModel = ConstantFeeModel(0) ## Set fees to $0 for High Freq. Trading
## Register a 20-bar SMA indicator for tracking the moving average of the
## long/short position and a RollingWindow to keep track of our
## most recent position values
self.sma = SimpleMovingAverage(20)
self.position = RollingWindow[Decimal](2)
## Warm up our 20-bar indicator
self.SetWarmup(20)
## Initialize a list to keep track of our position value, a period counter
## to assist in tracking our position relative to the SMA,
## and alpha + beta to represent position sizes in our assets
self.alpha = None
self.beta = None
self.Invested = False
def OnData(self, data):
## If one or more of the symbols doesn't have a TradeBar for a given slice, then
## skip this slice and do nothing until both symbols have data
for symbol in self.symbols:
if not data.Bars.ContainsKey(symbol): return
## We want to make and initial calculation of alpha and beta such that our position
## in each asset is 50% of our total available cash.
if (self.alpha is None) and (self.beta is None):
self.alpha = self.CalculateOrderQuantity(self.symbols[0], 0.5)
self.beta = self.CalculateOrderQuantity(self.symbols[1], 0.5)
## We want to keep updating the SMA indicator and our own position
## value list while the algorithm is warming-up
if not self.sma.IsReady:
position_value = (self.alpha * data[self.symbols[0]].Close) - (self.beta * data[self.symbols[1]].Close)
self.sma.Update(data[self.symbols[0]].EndTime, position_value)
self.position.Add(position_value)
return
## Calculate our position value here, which we then use to update the SMA
position_value = (self.alpha * data[self.symbols[0]].Close) - (self.beta * data[self.symbols[1]].Close)
self.sma.Update(data[self.symbols[0]].EndTime, position_value)
self.position.Add(position_value)
## Check to see if the position has crossed over the SMA before we liquidate
## our positions. This prevents immediate liquidation of a position after entering it
if not self.Invested:
## Position value greater than SMA indicates that we should 'sell our portfolio' since it will revert back to the mean value
## This means go long 'GOOGL' and go short 'GOOG'
if position_value >= self.sma.Current.Value:
insight1 = Insight.Price(self.symbols[1], timedelta(minutes=5), InsightDirection.Up)
insight2 = Insight.Price(self.symbols[0], timedelta(minutes=5), InsightDirection.Down)
self.EmitInsights( Insight.Group ( [insight1, insight2] ) )
self.Log('Insight Emitted')
self.SetHoldings(self.symbols[1], 0.5)
self.SetHoldings(self.symbols[0], -0.5)
self.Invested = True
## Position value greater than SMA indicates that we should 'buy our portfolio' since it will revert back to the mean value
## This means go short 'GOOGL' and go long 'GOOG'
if position_value < self.sma.Current.Value:
insight1 = Insight.Price(self.symbols[1], timedelta(minutes=5), InsightDirection.Down)
insight2 = Insight.Price(self.symbols[0], timedelta(minutes=5), InsightDirection.Up)
self.EmitInsights( Insight.Group ( [insight1, insight2] ) )
self.Log('Insight Emitted')
self.SetHoldings(self.symbols[1], -0.5)
self.SetHoldings(self.symbols[0], 0.5)
self.Invested = True
## If we are invested and the long/short position has crossed the SMA line, then we close our positions
if self.Invested and self.crossed_sma():
self.Liquidate()
self.Invested = False
## Helper function to check if the long/short position has crossed the SMA
def crossed_sma(self):
if (self.position[0] >= self.sma.Current.Value) and (self.position[1] < self.sma.Current.Value):
return True
elif (self.position[0] < self.sma.Current.Value) and (self.position[1] >= self.sma.Current.Value):
return True
else:
return False
@@ -0,0 +1,125 @@
# 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 clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm.Framework import QCAlgorithmFramework
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
#
# Identify "pumped" penny stocks and predict that the price of a "Pumped" penny stock reverts to mean
#
# This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
#
class SykesShortMicroCapAlpha(QCAlgorithmFramework):
''' Alpha Streams: Benchmark Alpha: Identify "pumped" penny stocks and predict that the price of a "pumped" penny stock reverts to mean'''
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetCash(100000)
# Set zero transaction fees
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))
# select stocks using PennyStockUniverseSelectionModel
self.UniverseSettings.Resolution = Resolution.Daily
self.SetUniverseSelection(PennyStockUniverseSelectionModel())
# Use SykesShortMicroCapAlphaModel to establish insights
self.SetAlpha(SykesShortMicroCapAlphaModel())
# Equally weigh securities in portfolio, based on insights
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
# Set Immediate Execution Model
self.SetExecution(ImmediateExecutionModel())
# Set Null Risk Management Model
self.SetRiskManagement(NullRiskManagementModel())
class SykesShortMicroCapAlphaModel(AlphaModel):
'''Uses ranking of intraday percentage difference between open price and close price to create magnitude and direction prediction for insights'''
def __init__(self, *args, **kwargs):
lookback = kwargs['lookback'] if 'lookback' in kwargs else 1
resolution = kwargs['resolution'] if 'resolution' in kwargs else Resolution.Daily
self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), lookback)
self.numberOfStocks = kwargs['numberOfStocks'] if 'numberOfStocks' in kwargs else 10
def Update(self, algorithm, data):
insights = []
symbolsRet = dict()
for security in algorithm.ActiveSecurities.Values:
if security.HasData:
open = security.Open
if open != 0:
# Intraday price change for penny stocks
symbolsRet[security.Symbol] = security.Close / open - 1
# Rank penny stocks on one day price change and retrieve list of ten "pumped" penny stocks
pumpedStocks = dict(sorted(symbolsRet.items(),
key = lambda kv: (-round(kv[1], 6), kv[0]))[0:self.numberOfStocks])
# Emit "down" insight for "pumped" penny stocks
for key,value in pumpedStocks.items():
insights.append(Insight.Price(key, self.predictionInterval, InsightDirection.Down, abs(value), None))
return insights
class PennyStockUniverseSelectionModel(FundamentalUniverseSelectionModel):
'''Defines a universe of penny stocks, as a universe selection model for the framework algorithm:
The stocks must have fundamental data
The stock must have positive previous-day close price
The stock must have volume between $1000000 and $10000 on the previous trading day
The stock must cost less than $5'''
def __init__(self):
super().__init__(False)
# Number of stocks in Coarse Universe
self.numberOfSymbolsCoarse = 500
self.lastMonth = -1
self.symbols = []
def SelectCoarse(self, algorithm, coarse):
month = algorithm.Time.month
if month == self.lastMonth:
return self.symbols
self.lastMonth = month
filtered = [x for x in coarse if x.HasFundamentalData
and 1000000 > x.Volume > 10000
and 5 > x.Price > 0]
# sort the stocks by dollar volume and take the top 500
top = sorted(filtered, key=lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse]
self.symbols = [ i.Symbol for i in top ]
return self.symbols
@@ -0,0 +1,110 @@
# 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 clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Data.Market import TradeBar
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Risk import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Selection import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Portfolio import PortfolioTarget, EqualWeightingPortfolioConstructionModel
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Orders.Slippage import ConstantSlippageModel
from datetime import datetime, timedelta
#
# In a perfect market, you could buy 100 EUR worth of USD, sell 100 EUR worth of GBP,
# and then use the GBP to buy USD and wind up with the same amount in USD as you received when
# you bought them with EUR. This relationship is expressed by the Triangle Exchange Rate, which is
#
# Triangle Exchange Rate = (A/B) * (B/C) * (C/A)
#
# where (A/B) is the exchange rate of A-to-B. In a perfect market, TER = 1, and so when
# there is a mispricing in the market, then TER will not be 1 and there exists an arbitrage opportunity.
#
# This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
#
class TriangleExchangeRateArbitrageAlgorithm(QCAlgorithmFramework):
def Initialize(self):
self.SetStartDate(2019, 2, 1) #Set Start Date
self.SetCash(100000) #Set Strategy Cash
# Set zero transaction fees
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))
## Select trio of currencies to trade where
## Currency A = USD
## Currency B = EUR
## Currency C = GBP
currencies = ['EURUSD','EURGBP','GBPUSD']
symbols = [ Symbol.Create(currency, SecurityType.Forex, Market.Oanda) for currency in currencies]
## Manual universe selection with tick-resolution data
self.UniverseSettings.Resolution = Resolution.Minute
self.SetUniverseSelection( ManualUniverseSelectionModel(symbols) )
self.SetAlpha(ForexTriangleArbitrageAlphaModel(Resolution.Minute, symbols))
## Set Equal Weighting Portfolio Construction Model
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
## Set Immediate Execution Model
self.SetExecution(ImmediateExecutionModel())
## Set Null Risk Management Model
self.SetRiskManagement(NullRiskManagementModel())
class ForexTriangleArbitrageAlphaModel(AlphaModel):
def __init__(self, insight_resolution, symbols):
self.insight_period = Time.Multiply(Extensions.ToTimeSpan(insight_resolution), 5)
self.symbols = symbols
def Update(self, algorithm, data):
## Check to make sure all currency symbols are present
for symbol in self.symbols:
if not data.Bars.ContainsKey(symbol) or symbol not in data.Keys:
return []
## Extract QuoteBars for all three Forex securities
bar_a = data[self.symbols[0]]
bar_b = data[self.symbols[1]]
bar_c = data[self.symbols[2]]
## Calculate the triangle exchange rate
## Bid(Currency A -> Currency B) * Bid(Currency B -> Currency C) * Bid(Currency C -> Currency A)
## If exchange rates are priced perfectly, then this yield 1. If it is different than 1, then an arbitrage opportunity exists
triangleRate = bar_a.Ask.Close / bar_b.Bid.Close / bar_c.Ask.Close
## If the triangle rate is significantly different than 1, then emit insights
if triangleRate > 1.0005:
return Insight.Group(
[
Insight.Price(self.symbols[0], self.insight_period, InsightDirection.Up, 0.0001, None),
Insight.Price(self.symbols[1], self.insight_period, InsightDirection.Down, 0.0001, None),
Insight.Price(self.symbols[2], self.insight_period, InsightDirection.Up, 0.0001, None)
] )
return []
@@ -15,14 +15,17 @@ 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 QCAlgorithm
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm.Framework import QCAlgorithmFramework
from datetime import timedelta, datetime
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel
from QuantConnect.Algorithm.Framework.Selection import ManualUniverseSelectionModel
from datetime import timedelta
#
# Leveraged ETFs (LETF) promise a fixed leverage ratio with respect to an underlying asset or an index.
@@ -33,35 +36,38 @@ from datetime import timedelta, datetime
# This alpha emits short-biased insight to capitalize on volatility decay for each listed pair of TL-ETFs, by rebalancing the
# ETFs with equal weights each day.
#
# This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and
# client funds can see an example of an alpha.
#
# This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
#
class TripleLeveragedETFPairVolatilityDecayAlphaAlgorithm(QCAlgorithmFramework):
class TripleLeverageETFPairVolatilityDecayAlpha(QCAlgorithmFramework):
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetCash(100000)
# Set zero transaction fees
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))
# 3X ETF pair tickers
# 3X ETF pair tickers
ultraLong = Symbol.Create("UGLD", SecurityType.Equity, Market.USA)
ultraShort = Symbol.Create("DGLD", SecurityType.Equity, Market.USA)
# Manually curated universe
self.UniverseSettings.Resolution = Resolution.Daily
self.SetUniverseSelection(ManualUniverseSelectionModel([ultraLong, ultraShort]))
# Select the demonstration alpha model
self.SetAlpha(RebalancingTripleLeveragedETFAlphaModel(ultraLong, ultraShort))
# Select our default model types
## Set Equal Weighting Portfolio Construction Model
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
## Set Immediate Execution Model
self.SetExecution(ImmediateExecutionModel())
## Set Null Risk Management Model
self.SetRiskManagement(NullRiskManagementModel())
@@ -69,21 +75,21 @@ class RebalancingTripleLeveragedETFAlphaModel(AlphaModel):
'''
Rebalance a pair of 3x leveraged ETFs and predict that the value of both ETFs in each pair will decrease.
'''
def __init__(self, ultraLong, ultraShort):
self.Name = "RebalancingTripleLeveragedETFAlphaModel"
def __init__(self, ultraLong, ultraShort):
# Giving an insight period 1 days.
self.period = timedelta(1)
self.magnitude = 0.001
self.ultraLong = ultraLong
self.ultraShort = ultraShort
self.Name = "RebalancingTripleLeveragedETFAlphaModel"
def Update(self, algorithm, data):
'''Emit an insight each day.'''
insights = []
magnitude = 0.001
# Giving an insight period 1 days.
period = timedelta(days=1)
insights.append(Insight.Price(self.ultraLong, period, InsightDirection.Down, magnitude))
insights.append(Insight.Price(self.ultraShort, period, InsightDirection.Down, magnitude))
return Insight.Group( insights )
return Insight.Group(
[
Insight.Price(self.ultraLong, self.period, InsightDirection.Down, self.magnitude),
Insight.Price(self.ultraShort, self.period, InsightDirection.Down, self.magnitude)
] )
@@ -0,0 +1,198 @@
# 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 clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Data.Consolidators import TradeBarConsolidator
from QuantConnect.Data.Market import TradeBar
from QuantConnect.Indicators import RollingWindow
from QuantConnect.Brokerages import BrokerageName
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm.Framework import QCAlgorithmFramework
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Selection import ManualUniverseSelectionModel
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel
from QuantConnect.Algorithm.Framework.Execution import ImmediateExecutionModel
from QuantConnect.Algorithm.Framework.Risk import MaximumDrawdownPercentPerSecurity
from datetime import timedelta
#
# This is a demonstration algorithm. It trades UVXY.
# Dual Thrust alpha model is used to produce insights.
# Those input parameters have been chosen that gave acceptable results on a series
# of random backtests run for the period from Oct, 2016 till Feb, 2019.
#
class VIXDualThrustAlpha(QCAlgorithmFramework):
def Initialize(self):
# -- STRATEGY INPUT PARAMETERS --
self.k1 = 0.63
self.k2 = 0.63
self.rangePeriod = 20
self.consolidatorBars = 30
# Settings
self.SetStartDate(2018, 10, 1)
self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin);
# Universe Selection
self.UniverseSettings.Resolution = Resolution.Minute # it's minute by default, but lets leave this param here
symbols = [Symbol.Create("SPY", SecurityType.Equity, Market.USA)]
self.SetUniverseSelection(ManualUniverseSelectionModel(symbols))
# Warming up
resolutionInTimeSpan = Extensions.ToTimeSpan(self.UniverseSettings.Resolution)
warmUpTimeSpan = Time.Multiply(resolutionInTimeSpan, self.consolidatorBars)
self.SetWarmUp(warmUpTimeSpan)
# Alpha Model
self.SetAlpha(DualThrustAlphaModel(self.k1, self.k2, self.rangePeriod, self.UniverseSettings.Resolution, self.consolidatorBars))
## Portfolio Construction
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
## Execution
self.SetExecution(ImmediateExecutionModel())
## Risk Management
self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.03))
class DualThrustAlphaModel(AlphaModel):
'''Alpha model that uses dual-thrust strategy to create insights
https://medium.com/@FMZ_Quant/dual-thrust-trading-strategy-2cc74101a626
or here:
https://www.quantconnect.com/tutorials/strategy-library/dual-thrust-trading-algorithm'''
def __init__(self,
k1,
k2,
rangePeriod,
resolution = Resolution.Daily,
barsToConsolidate = 1):
'''Initializes a new instance of the class
Args:
k1: Coefficient for upper band
k2: Coefficient for lower band
rangePeriod: Amount of last bars to calculate the range
resolution: The resolution of data sent into the EMA indicators
barsToConsolidate: If we want alpha to work on trade bars whose length is different
from the standard resolution - 1m 1h etc. - we need to pass this parameters along
with proper data resolution'''
# coefficient that used to determinte upper and lower borders of a breakout channel
self.k1 = k1
self.k2 = k2
# period the range is calculated over
self.rangePeriod = rangePeriod
# initialize with empty dict.
self.symbolDataBySymbol = dict()
# time for bars we make the calculations on
resolutionInTimeSpan = Extensions.ToTimeSpan(resolution)
self.consolidatorTimeSpan = Time.Multiply(resolutionInTimeSpan, barsToConsolidate)
# in 5 days after emission an insight is to be considered expired
self.period = timedelta(5)
def Update(self, algorithm, data):
insights = []
for symbol, symbolData in self.symbolDataBySymbol.items():
if not symbolData.IsReady:
continue
holding = algorithm.Portfolio[symbol]
price = algorithm.Securities[symbol].Price
# buying condition
# - (1) price is above upper line
# - (2) and we are not long. this is a first time we crossed the line lately
if price > symbolData.UpperLine and not holding.IsLong:
insightCloseTimeUtc = algorithm.UtcTime + self.period
insights.append(Insight.Price(symbol, insightCloseTimeUtc, InsightDirection.Up))
# selling condition
# - (1) price is lower that lower line
# - (2) and we are not short. this is a first time we crossed the line lately
if price < symbolData.LowerLine and not holding.IsShort:
insightCloseTimeUtc = algorithm.UtcTime + self.period
insights.append(Insight.Price(symbol, insightCloseTimeUtc, InsightDirection.Down))
return insights
def OnSecuritiesChanged(self, algorithm, changes):
# added
for symbol in [x.Symbol for x in changes.AddedSecurities]:
if symbol not in self.symbolDataBySymbol:
# add symbol/symbolData pair to collection
symbolData = self.SymbolData(symbol, self.k1, self.k2, self.rangePeriod, self.consolidatorTimeSpan)
self.symbolDataBySymbol[symbol] = symbolData
# register consolidator
algorithm.SubscriptionManager.AddConsolidator(symbol, symbolData.GetConsolidator())
# removed
for symbol in [x.Symbol for x in changes.RemovedSecurities]:
symbolData = self.symbolDataBySymbol.pop(symbol, None)
if symbolData is None:
algorithm.Error("Unable to remove data from collection: DualThrustAlphaModel")
else:
# unsubscribe consolidator from data updates
algorithm.SubscriptionManager.RemoveConsolidator(symbol, symbolData.GetConsolidator())
class SymbolData:
'''Contains data specific to a symbol required by this model'''
def __init__(self, symbol, k1, k2, rangePeriod, consolidatorResolution):
self.Symbol = symbol
self.rangeWindow = RollingWindow[TradeBar](rangePeriod)
self.consolidator = TradeBarConsolidator(consolidatorResolution);
def onDataConsolidated(sender, consolidated):
# add new tradebar to
self.rangeWindow.Add(consolidated)
if self.rangeWindow.IsReady:
hh = max([x.High for x in self.rangeWindow])
hc = max([x.Close for x in self.rangeWindow])
lc = min([x.Close for x in self.rangeWindow])
ll = min([x.Low for x in self.rangeWindow])
range = max([hh - lc, hc - ll])
self.UpperLine = consolidated.Close + k1 * range
self.LowerLine = consolidated.Close - k2 * range
# event fired at new consolidated trade bar
self.consolidator.DataConsolidated += onDataConsolidated
# Returns the interior consolidator
def GetConsolidator(self):
return self.consolidator
@property
def IsReady(self):
return self.rangeWindow.IsReady
@@ -27,7 +27,7 @@ import numpy as np
### <summary>
### Algorithm demonstrating FOREX asset types and requesting history on them in bulk. As FOREX uses
### QuoteBars you should request slices or
### QuoteBars you should request slices
### </summary>
### <meta name="tag" content="using data" />
### <meta name="tag" content="history and warm up" />
@@ -46,21 +46,31 @@ class BasicTemplateOptionsConsolidationAlgorithm(QCAlgorithm):
def OnData(self,slice):
pass
def OnDataConsolidated(self, sender, quoteBar):
self.Log("OnDataConsolidated called on " + str(self.Time))
def OnQuoteBarConsolidated(self, sender, quoteBar):
self.Log("OnQuoteBarConsolidated called on " + str(self.Time))
self.Log(str(quoteBar))
def OnTradeBarConsolidated(self, sender, tradeBar):
self.Log("OnTradeBarConsolidated called on " + str(self.Time))
self.Log(str(tradeBar))
def OnSecuritiesChanged(self, changes):
for security in changes.AddedSecurities:
if security.Type == SecurityType.Equity:
consolidator = TradeBarConsolidator(timedelta(minutes=5))
consolidator.DataConsolidated += self.OnTradeBarConsolidated
else:
consolidator = QuoteBarConsolidator(timedelta(minutes=5))
consolidator.DataConsolidated += self.OnDataConsolidated
consolidator.DataConsolidated += self.OnQuoteBarConsolidated
self.SubscriptionManager.AddConsolidator(security.Symbol, consolidator)
self.consolidators[security.Symbol] = consolidator
for security in changes.RemovedSecurities:
consolidator = self.consolidators.pop(security.Symbol)
self.SubscriptionManager.RemoveConsolidator(security.Symbol, consolidator)
consolidator.DataConsolidated -= self.OnDataConsolidated
if security.Type == SecurityType.Equity:
consolidator.DataConsolidated -= self.OnTradeBarConsolidated
else:
consolidator.DataConsolidated -= self.OnQuoteBarConsolidated
@@ -22,7 +22,6 @@ from QuantConnect.Algorithm import *
from QuantConnect.Securities.Option import OptionPriceModels
from QuantConnect.Data.UniverseSelection import *
from datetime import timedelta
import decimal as d
### <summary>
### Example demonstrating how to access to options history for a given underlying equity security.
@@ -26,17 +26,15 @@ class ScheduledEventsBenchmark(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2011, 1, 1)
self.SetEndDate(2018, 1, 1)
self.SetCash(100000)
self.AddEquity("SPY", Resolution.Minute)
self.SetStartDate(2011, 1, 1)
self.SetEndDate(2018, 1, 1)
self.SetCash(100000)
self.AddEquity("SPY")
for i in range(100):
for i in range(300):
self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", i), self.Rebalance)
self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", i), self.Rebalance)
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.Every(timedelta(seconds=5)), self.Rebalance)
def OnData(self, data):
pass
+1 -2
View File
@@ -24,7 +24,6 @@ from QuantConnect.Indicators import *
from QuantConnect.Data import SubscriptionDataSource
from QuantConnect.Python import PythonData
from datetime import date, timedelta, datetime
import decimal
import numpy as np
import math
import json
@@ -200,7 +199,7 @@ class Cape(PythonData):
# DateTime.ParseExact() and explicit declare the format your data source has.
index.Time = datetime.strptime(data[0], "%Y-%m")
index["Cape"] = float(data[10])
index.Value = decimal.Decimal(data[10])
index.Value = data[10]
except ValueError:
@@ -13,19 +13,15 @@
from clr import AddReference
AddReference("System.Core")
AddReference("System.Collections")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
from System import *
from System.Collections.Generic import List
from QuantConnect import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Data.UniverseSelection import *
from math import ceil
import numpy as np
import pandas as pd
import scipy as sp
from itertools import groupby
### <summary>
### Demonstration of how to estimate constituents of QC500 index based on the company fundamentals
@@ -40,74 +36,67 @@ class ConstituentsQC500GeneratorAlgorithm(QCAlgorithm):
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(2018, 1, 1) #Set Start Date
self.SetEndDate(2018, 1, 3) #Set End Date
self.SetCash(50000) #Set Strategy Cash
self.UniverseSettings.Resolution = Resolution.Daily
self.SetStartDate(2018, 1, 1) # Set Start Date
self.SetEndDate(2019, 1, 1) # Set End Date
self.SetCash(100000) # Set Strategy Cash
# this add universe method accepts two parameters:
# - coarse selection function: accepts an IEnumerable<CoarseFundamental> and returns an IEnumerable<Symbol>
# - fine selection function: accepts an IEnumerable<FineFundamental> and returns an IEnumerable<Symbol>
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
self.spy = self.AddEquity("SPY", Resolution.Daily)
self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.At(0, 0), self.monthly_rebalance)
self.num_coarse = 1000
self.num_fine = 500
self.dollar_volume = {}
self.rebalance = True
self.numberOfSymbolsCoarse = 1000
self.numberOfSymbolsFine = 500
self.dollarVolumeBySymbol = {}
self.symbols = []
self.lastMonth = -1
def CoarseSelectionFunction(self, coarse):
if not self.rebalance: return []
if self.Time.month == self.lastMonth:
return self.symbols
# 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
filtered = [x for x in coarse if x.HasFundamentalData
and x.Volume > 0
and x.Price > 0]
# sort the stocks by dollar volume and take the top 1000
sort_filtered = sorted(filtered, key=lambda x: x.DollarVolume, reverse=True)[:self.num_coarse]
for i in sort_filtered:
self.dollar_volume[i.Symbol.Value] = i.DollarVolume
filtered = [x for x in coarse if x.HasFundamentalData and x.Volume > 0 and x.Price > 0]
sortedByDollarVolume = sorted(filtered, key = lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse]
self.symbols.clear()
self.dollarVolumeBySymbol.clear()
for x in sortedByDollarVolume:
self.symbols.append(x.Symbol)
self.dollarVolumeBySymbol[x.Symbol] = x.DollarVolume
# return the symbol objects our sorted collection
return [x.Symbol for x in sort_filtered]
return self.symbols
def FineSelectionFunction(self, fine):
if not self.rebalance: return []
self.rebalance = False
if self.Time.month == self.lastMonth:
return self.symbols
self.lastMonth = self.Time.month
# 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
filtered_fine = [x for x in fine if (x.CompanyReference.CountryId == "USA")
and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
and ((self.Time - x.SecurityReference.IPODate).days > 180)
and x.EarningReports.BasicAverageShares.ThreeMonths * (x.EarningReports.BasicEPS.TwelveMonths*x.ValuationRatios.PERatio) > 5e8]
filtered = [x for x in fine if x.CompanyReference.CountryId == "USA"
and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
and (self.Time - x.SecurityReference.IPODate).days > 180
and x.EarningReports.BasicAverageShares.ThreeMonths * (x.EarningReports.BasicEPS.TwelveMonths*x.ValuationRatios.PERatio) > 5e8]
count = len(filtered_fine)
if count == 0: return []
# select stocks with top dollar volume in every single sector
for i in filtered_fine:
i.DollarVolume = self.dollar_volume[i.Symbol.Value]
percent = float(self.num_fine/count)
group_by_code = {}
top_list = []
for code in ["N", "M", "U", "T", "B", "I"]:
group_by_code[code] = list(filter(lambda x: x.CompanyReference.IndustryTemplateCode == code, filtered_fine))
top = sorted(group_by_code[code], key=lambda x: x.DollarVolume, reverse = True)[:ceil(len(group_by_code[code])*percent)]
top_list.append(top)
joined_list = top_list[0]
for ls in top_list[1:]:
joined_list += ls
self.symbols = [x.Symbol for x in joined_list][:self.num_fine]
self.Log(",".join(sorted(i.Value for i in self.symbols)))
return self.symbols
sortedByDollarVolume = []
sortedBySector = sorted(filtered, key = lambda x: x.CompanyReference.IndustryTemplateCode)
def OnData(self, data):
pass
percent = self.numberOfSymbolsFine/float(len(sortedBySector))
def monthly_rebalance(self):
self.rebalance = True
# select stocks with top dollar volume in every single sector
for code, g in groupby(sortedBySector, lambda x: x.CompanyReference.IndustryTemplateCode):
y = sorted(g, key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse = True)
c = ceil(len(y) * percent)
sortedByDollarVolume.extend(y[:c])
sortedByDollarVolume = sorted(sortedByDollarVolume, key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse=True)
self.symbols = [x.Symbol for x in sortedByDollarVolume[:self.numberOfSymbolsFine]]
return self.symbols
+3 -2
View File
@@ -68,8 +68,9 @@ class CustomChartingAlgorithm(QCAlgorithm):
self.lastPrice = slice["SPY"].Close
if self.fastMA == 0: self.fastMA = self.lastPrice
if self.slowMA == 0: self.slowMA = self.lastPrice
self.fastMA = (d.Decimal(0.01) * self.lastPrice) + (d.Decimal(0.99) * self.fastMA)
self.slowMA = (d.Decimal(0.001) * self.lastPrice) + (d.Decimal(0.999) * self.slowMA)
self.fastMA = (0.01 * self.lastPrice) + (0.99 * self.fastMA)
self.slowMA = (0.001 * self.lastPrice) + (0.999 * self.slowMA)
if self.Time > self.resample:
self.resample = self.Time + self.resamplePeriod
@@ -23,7 +23,6 @@ from QuantConnect.Data import SubscriptionDataSource
from QuantConnect.Python import PythonData
from datetime import date, timedelta, datetime
import decimal
import numpy as np
import json
@@ -82,7 +81,7 @@ class Bitcoin(PythonData):
liveBTC = json.loads(line)
# If value is zero, return None
value = decimal.Decimal(liveBTC["last"])
value = liveBTC["last"]
if value == 0: return None
coin.Time = datetime.now()
@@ -109,7 +108,7 @@ class Bitcoin(PythonData):
data = line.split(',')
# If value is zero, return None
value = decimal.Decimal(data[4])
value = data[4]
if value == 0: return None
coin.Time = datetime.strptime(data[0], "%Y-%m-%d")
+3 -4
View File
@@ -22,7 +22,6 @@ from QuantConnect.Algorithm import *
from QuantConnect.Data import SubscriptionDataSource
from QuantConnect.Python import PythonData
from datetime import date, timedelta, datetime
import decimal
import numpy as np
import math
import json
@@ -68,7 +67,7 @@ class CustomDataNIFTYAlgorithm(QCAlgorithm):
if self.Time.weekday() != 2: return
cur_qnty = self.Portfolio["NIFTY"].Quantity
quantity = decimal.Decimal(math.floor(self.Portfolio.MarginRemaining * decimal.Decimal(0.9) / data["NIFTY"].Close))
quantity = math.floor(self.Portfolio.MarginRemaining * 0.9) / data["NIFTY"].Close
hi_nifty = max(price.NiftyPrice for price in self.prices)
lo_nifty = min(price.NiftyPrice for price in self.prices)
@@ -99,7 +98,7 @@ class Nifty(PythonData):
# 2011-09-13 7792.9 7799.9 7722.65 7748.7 116534670 6107.78
data = line.split(',')
index.Time = datetime.strptime(data[0], "%Y-%m-%d")
index.Value = decimal.Decimal(data[4])
index.Value = data[4]
index["Open"] = float(data[1])
index["High"] = float(data[2])
index["Low"] = float(data[3])
@@ -128,7 +127,7 @@ class DollarRupee(PythonData):
try:
data = line.split(',')
currency.Time = datetime.strptime(data[0], "%Y-%m-%d")
currency.Value = decimal.Decimal(data[1])
currency.Value = data[1]
currency["Close"] = float(data[1])
except ValueError:
@@ -23,7 +23,6 @@ from QuantConnect.Data import SubscriptionDataSource
from QuantConnect.Python import PythonData
from datetime import datetime
import decimal
import json
### <summary>
@@ -75,7 +74,7 @@ class Bitcoin(PythonData):
liveBTC = json.loads(line)
# If value is zero, return None
value = decimal.Decimal(liveBTC["last"])
value = liveBTC["last"]
if value == 0: return None
coin.Time = datetime.now()
@@ -22,7 +22,6 @@ from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Data import SubscriptionDataSource
from QuantConnect.Python import PythonData
from datetime import date, timedelta, datetime
import decimal as d
### <summary>
### This algorithm shows how to grab symbols from an external api each day
+2 -3
View File
@@ -24,7 +24,6 @@ from QuantConnect.Orders.Fees import *
from QuantConnect.Securities import *
from QuantConnect.Orders.Fills import *
import numpy as np
import decimal as d
import random
### <summary>
@@ -102,7 +101,7 @@ class CustomFeeModel(FeeModel):
# custom fee math
fee = max(1, parameters.Security.Price
* parameters.Order.AbsoluteQuantity
* d.Decimal(0.00001))
* 0.00001)
self.algorithm.Log("CustomFeeModel: " + str(fee))
return OrderFee(CashAmount(fee, "USD"))
@@ -112,6 +111,6 @@ class CustomSlippageModel:
def GetSlippageApproximation(self, asset, order):
# custom slippage math
slippage = asset.Price * d.Decimal(0.0001 * np.log10(2*float(order.AbsoluteQuantity)))
slippage = asset.Price * 0.0001 * np.log10(2*float(order.AbsoluteQuantity))
self.algorithm.Log("CustomSlippageModel: " + str(slippage))
return slippage
@@ -25,7 +25,6 @@ from datetime import date, timedelta, datetime
from System.Collections.Generic import List
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Data.UniverseSelection import *
import decimal as d
import numpy as np
import math
import json
@@ -64,7 +63,7 @@ class DropboxBaseDataUniverseSelectionAlgorithm(QCAlgorithm):
# start fresh
self.Liquidate()
percentage = 1 / d.Decimal(slice.Bars.Count)
percentage = 1 / slice.Bars.Count
for tradeBar in slice.Bars.Values:
self.SetHoldings(tradeBar.Symbol, percentage)
@@ -20,7 +20,6 @@ from System import *
from QuantConnect import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Data.UniverseSelection import *
import decimal as d
import base64
### <summary>
@@ -78,7 +77,7 @@ class DropboxUniverseSelectionAlgorithm(QCAlgorithm):
# start fresh
self.Liquidate()
percentage = 1 / d.Decimal(slice.Bars.Count)
percentage = 1 / slice.Bars.Count
for tradeBar in slice.Bars.Values:
self.SetHoldings(tradeBar.Symbol, percentage)
@@ -23,9 +23,7 @@ from QuantConnect.Data import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from System.Collections.Generic import List
import decimal as d
from datetime import datetime, timedelta
from decimal import Decimal
### <summary>
### Strategy example using a portfolio of ETF Global Rotation
@@ -89,7 +87,7 @@ class ETFGlobalRotationAlgorithm(QCAlgorithm):
if (self.Portfolio[bestGrowth[0]].Quantity == 0):
self.Log("PREBUY>>LIQUIDATE>>")
self.Liquidate()
self.Log(">>BUY>>" + str(bestGrowth[0]) + "@" + str(Decimal(100) * bestGrowth[1].Current.Value))
self.Log(">>BUY>>" + str(bestGrowth[0]) + "@" + str(100 * bestGrowth[1].Current.Value))
qty = self.Portfolio.MarginRemaining / self.Securities[bestGrowth[0]].Close
self.MarketOrder(bestGrowth[0], int(qty))
else:
@@ -23,7 +23,6 @@ from QuantConnect.Data import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from System.Collections.Generic import List
import decimal as d
### <summary>
### In this algorithm we demonstrate how to perform some technical analysis as
@@ -92,7 +91,7 @@ class EmaCrossUniverseSelectionAlgorithm(QCAlgorithm):
class SymbolData(object):
def __init__(self, symbol):
self.symbol = symbol
self.tolerance = d.Decimal(1.01)
self.tolerance = 1.01
self.fast = ExponentialMovingAverage(100)
self.slow = ExponentialMovingAverage(300)
self.is_uptrend = False
@@ -105,4 +104,4 @@ class SymbolData(object):
self.is_uptrend = fast > slow * self.tolerance
if self.is_uptrend:
self.scale = (fast - slow) / ((fast + slow) / d.Decimal(2.0))
self.scale = (fast - slow) / ((fast + slow) / 2.0)
@@ -27,7 +27,6 @@ from QuantConnect.Securities import *
from QuantConnect.Data.Market import *
from QuantConnect.Data.Consolidators import *
import decimal as d
from datetime import timedelta
from math import floor
+2 -3
View File
@@ -21,7 +21,6 @@ from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Securities import *
from datetime import timedelta
import decimal as d
import numpy as np
### <summary>
@@ -43,7 +42,7 @@ class FuturesMomentumAlgorithm(QCAlgorithm):
self.SetCash(100000)
fastPeriod = 20
slowPeriod = 60
self._tolerance = d.Decimal(1 + 0.001)
self._tolerance = 1 + 0.001
self.IsUpTrend = False
self.IsDownTrend = False
self.SetWarmUp(max(fastPeriod, slowPeriod))
@@ -65,7 +64,7 @@ class FuturesMomentumAlgorithm(QCAlgorithm):
if (not self.Portfolio.Invested) and self.IsUpTrend:
for chain in slice.FuturesChains:
# find the front contract expiring no earlier than in 90 days
contracts = filter(lambda x: x.Expiry > self.Time + timedelta(90), chain.Value)
contracts = list(filter(lambda x: x.Expiry > self.Time + timedelta(90), chain.Value))
# if there is any contract, trade the front contract
if len(contracts) == 0: continue
contract = sorted(contracts, key = lambda x: x.Expiry, reverse=True)[0]
+4 -5
View File
@@ -25,7 +25,6 @@ from QuantConnect.Data import *
from QuantConnect.Indicators import *
from QuantConnect.Orders import *
from QuantConnect.Securities import *
import decimal as d
### <summary>
### Regression test for history and warm up using the data available in open source.
@@ -111,7 +110,7 @@ class IndicatorWarmupAlgorithm(QCAlgorithm):
def Update(self):
self.IsReady = self.Close.IsReady and self.ADX.IsReady and self.EMA.IsReady and self.MACD.IsReady
tolerance = d.Decimal(1 - self.PercentTolerance)
tolerance = 1 - self.PercentTolerance
self.IsUptrend = self.MACD.Signal.Current.Value > self.MACD.Current.Value * tolerance and\
self.EMA.Current.Value > self.Close.Current.Value * tolerance
@@ -147,7 +146,7 @@ class IndicatorWarmupAlgorithm(QCAlgorithm):
limit = 0
qty = self.Security.Holdings.Quantity
exitTolerance = d.Decimal(1 + 2 * self.PercentTolerance)
exitTolerance = 1 + 2 * self.PercentTolerance
if self.Security.Holdings.IsLong and self.Close.Current.Value * exitTolerance < self.EMA.Current.Value:
limit = self.Security.High
elif self.Security.Holdings.IsShort and self.Close.Current.Value > self.EMA.Current.Value * exitTolerance:
@@ -164,8 +163,8 @@ class IndicatorWarmupAlgorithm(QCAlgorithm):
# if we just finished entering, place a stop loss as well
if self.Security.Invested:
stop = fill.FillPrice*d.Decimal(1 - self.PercentGlobalStopLoss) if self.Security.Holdings.IsLong \
else fill.FillPrice*d.Decimal(1 + self.PercentGlobalStopLoss)
stop = fill.FillPrice*(1 - self.PercentGlobalStopLoss) if self.Security.Holdings.IsLong \
else fill.FillPrice*(1 + self.PercentGlobalStopLoss)
self.__currentStopLoss = self.__algorithm.StopMarketOrder(self.Symbol, -qty, stop, "StopLoss at: {0}".format(stop))
+1 -2
View File
@@ -27,7 +27,6 @@ from QuantConnect.Python import PythonData
import numpy as np
from datetime import datetime
import decimal
import json
@@ -103,7 +102,7 @@ class Bitcoin(PythonData):
liveBTC = json.loads(line)
# If value is zero, return None
value = decimal.Decimal(liveBTC["last"])
value = liveBTC["last"]
if value == 0: return None
coin.Time = datetime.now()
@@ -21,7 +21,6 @@ from QuantConnect import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import QCAlgorithm
import numpy as np
import decimal as d
from datetime import datetime, timedelta
### <summary>
@@ -61,7 +60,7 @@ class MarginCallEventsAlgorithm(QCAlgorithm):
for order in requests:
# liquidate an extra 10% each time we get a margin call to give us more padding
newQuantity = int(np.sign(order.Quantity) * order.Quantity * d.Decimal(1.1))
newQuantity = int(np.sign(order.Quantity) * order.Quantity * 1.1)
requests.remove(order)
requests.append(SubmitOrderRequest(order.OrderType, order.SecurityType, order.Symbol, newQuantity, order.StopPrice, order.LimitPrice, self.Time, "OnMarginCall"))
@@ -74,6 +73,6 @@ class MarginCallEventsAlgorithm(QCAlgorithm):
# a chance to prevent a margin call from occurring
spyHoldings = self.Securities["SPY"].Holdings.Quantity
shares = int(-spyHoldings * d.Decimal(0.005))
shares = int(-spyHoldings * 0.005)
self.Error("{0} - OnMarginCallWarning(): Liquidating {1} shares of SPY to avoid margin call.".format(self.Time, shares))
self.MarketOrder("SPY", shares)
@@ -21,7 +21,6 @@ from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
import decimal as d
### <summary>
### In this example we look at the canonical 15/30 day moving average cross. This algorithm
@@ -75,7 +74,7 @@ class MovingAverageCrossAlgorithm(QCAlgorithm):
# we only want to go long if we're currently short or flat
if holdings <= 0:
# if the fast is greater than the slow, we'll go long
if self.fast.Current.Value > self.slow.Current.Value * d.Decimal(1 + tolerance):
if self.fast.Current.Value > self.slow.Current.Value *(1 + tolerance):
self.Log("BUY >> {0}".format(self.Securities["SPY"].Price))
self.SetHoldings("SPY", 1.0)
+14 -15
View File
@@ -21,7 +21,6 @@ from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Orders import *
from QuantConnect.Data import *
import decimal as d
### <summary>
### In this algorithm we submit/update/cancel each order type
@@ -113,11 +112,11 @@ class OrderTicketDemoAlgorithm(QCAlgorithm):
# submit a limit order to buy 10 shares at .1% below the bar's close
close = self.Securities[self.spy.Value].Close
newTicket = self.LimitOrder(self.spy, 10, close * d.Decimal(.999))
newTicket = self.LimitOrder(self.spy, 10, close * .999)
self.__openLimitOrders.append(newTicket)
# submit another limit order to sell 10 shares at .1% above the bar's close
newTicket = self.LimitOrder(self.spy, -10, close * d.Decimal(1.001))
newTicket = self.LimitOrder(self.spy, -10, close * 1.001)
self.__openLimitOrders.append(newTicket)
# when we submitted new limit orders we placed them into this list,
@@ -133,8 +132,8 @@ class OrderTicketDemoAlgorithm(QCAlgorithm):
return
# if niether order has filled, bring in the limits by a penny
newLongLimit = longOrder.Get(OrderField.LimitPrice) + d.Decimal(0.01)
newShortLimit = shortOrder.Get(OrderField.LimitPrice) - d.Decimal(0.01)
newLongLimit = longOrder.Get(OrderField.LimitPrice) + 0.01
newShortLimit = shortOrder.Get(OrderField.LimitPrice) - 0.01
self.Log("Updating limits - Long: {0:.2f} Short: {1:.2f}".format(newLongLimit, newShortLimit))
updateOrderFields = UpdateOrderFields()
@@ -165,12 +164,12 @@ class OrderTicketDemoAlgorithm(QCAlgorithm):
# a long stop is triggered when the price rises above the value
# so we'll set a long stop .25% above the current bar's close
close = self.Securities[self.spy.Value].Close
newTicket = self.StopMarketOrder(self.spy, 10, close * d.Decimal(1.0025))
newTicket = self.StopMarketOrder(self.spy, 10, close * 1.0025)
self.__openStopMarketOrders.append(newTicket)
# a short stop is triggered when the price falls below the value
# so we'll set a short stop .25% below the current bar's close
newTicket = self.StopMarketOrder(self.spy, -10, close * d.Decimal(.9975))
newTicket = self.StopMarketOrder(self.spy, -10, close * .9975)
self.__openStopMarketOrders.append(newTicket)
# when we submitted new stop market orders we placed them into this list,
@@ -184,8 +183,8 @@ class OrderTicketDemoAlgorithm(QCAlgorithm):
return
# if neither order has filled, bring in the stops by a penny
newLongStop = longOrder.Get(OrderField.StopPrice) - d.Decimal(0.01)
newShortStop = shortOrder.Get(OrderField.StopPrice) + d.Decimal(0.01)
newLongStop = longOrder.Get(OrderField.StopPrice) - 0.01
newShortStop = shortOrder.Get(OrderField.StopPrice) + 0.01
self.Log("Updating stops - Long: {0:.2f} Short: {1:.2f}".format(newLongStop, newShortStop))
updateOrderFields = UpdateOrderFields()
@@ -224,7 +223,7 @@ class OrderTicketDemoAlgorithm(QCAlgorithm):
# so make the limit price a little higher than the stop price
close = self.Securities[self.spy.Value].Close
newTicket = self.StopLimitOrder(self.spy, 10, close * d.Decimal(1.001), close * d.Decimal(1.0025))
newTicket = self.StopLimitOrder(self.spy, 10, close * 1.001, close * 1.0025)
self.__openStopLimitOrders.append(newTicket)
# a short stop is triggered when the price falls below the
@@ -233,7 +232,7 @@ class OrderTicketDemoAlgorithm(QCAlgorithm):
# gauranteed to get at least the limit price for our fills,
# so make the limit price a little softer than the stop price
newTicket = self.StopLimitOrder(self.spy, -10, close * d.Decimal(.999), close * d.Decimal(0.9975))
newTicket = self.StopLimitOrder(self.spy, -10, close * .999, close * 0.9975)
self.__openStopLimitOrders.append(newTicket)
# when we submitted new stop limit orders we placed them into this list,
@@ -247,10 +246,10 @@ class OrderTicketDemoAlgorithm(QCAlgorithm):
# if neither order has filled, bring in the stops/limits in by a penny
newLongStop = longOrder.Get(OrderField.StopPrice) - d.Decimal(0.01)
newLongLimit = longOrder.Get(OrderField.LimitPrice) + d.Decimal(0.01)
newShortStop = shortOrder.Get(OrderField.StopPrice) + d.Decimal(0.01)
newShortLimit = shortOrder.Get(OrderField.LimitPrice) - d.Decimal(0.01)
newLongStop = longOrder.Get(OrderField.StopPrice) - 0.01
newLongLimit = longOrder.Get(OrderField.LimitPrice) + 0.01
newShortStop = shortOrder.Get(OrderField.StopPrice) + 0.01
newShortLimit = shortOrder.Get(OrderField.LimitPrice) - 0.01
self.Log("Updating stops - Long: {0:.2f} Short: {1:.2f}".format(newLongStop, newShortStop))
self.Log("Updating limits - Long: {0:.2f} Short: {1:.2f}".format(newLongLimit, newShortLimit))
+2 -3
View File
@@ -22,7 +22,6 @@ from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from QuantConnect.Parameters import *
import decimal as d
### <summary>
### Demonstration of the parameter system of QuantConnect. Using parameters you can pass the values required into C# algorithms for optimization.
@@ -62,7 +61,7 @@ class ParameterizedAlgorithm(QCAlgorithm):
fast = self.fast.Current.Value
slow = self.slow.Current.Value
if fast > slow * d.Decimal(1.001):
if fast > slow * 1.001:
self.SetHoldings("SPY", 1)
elif fast < slow * d.Decimal(0.999):
elif fast < slow * 0.999:
self.Liquidate("SPY")
@@ -22,7 +22,6 @@ from QuantConnect.Algorithm import *
from QuantConnect.Data import SubscriptionDataSource
from QuantConnect.Python import PythonData
from datetime import datetime, timedelta
import decimal
### <summary>
### Using weather in NYC to rebalance portfolio. Assumption is people are happier when its warm.
@@ -86,7 +85,7 @@ class Weather(PythonData):
weather.Time = datetime.strptime(data[0], '%Y-%m-%d') + timedelta(hours=20) # Make sure we only get this data AFTER trading day - don't want forward bias.
# If the second column is an invalid value (empty string), return None. The algorithm will discard it.
if not data[2]: return None
weather.Value = decimal.Decimal(data[2])
weather.Value = data[2]
weather["Max.C"] = float(data[1]) # Using a dot in the propety name, it will capitalize the first letter of each word:
weather["Min.C"] = float(data[3]) # Max.C -> MaxC and Min.C -> MinC
+2 -2
View File
@@ -38,7 +38,7 @@ class QuandlImporterAlgorithm(QCAlgorithm):
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.quandlCode = "SSE/YHO"
self.quandlCode = "WIKI/IBM"
Quandl.SetAuthCode("JjAt5_5Ggmmoe5zUKipm")
self.SetStartDate(2014,4,1) #Set Start Date
self.SetEndDate(datetime.today() - timedelta(1)) #Set End Date
@@ -59,4 +59,4 @@ class QuandlCustomColumns(PythonQuandl):
'''Custom quandl data type for setting customized value column name. Value column is used for the primary trading calculations and charting.'''
def __init__(self):
# Define ValueColumnName: cannot be None, Empty or non-existant column name
self.ValueColumnName = "last"
self.ValueColumnName = "adj. close"
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@@ -37,11 +37,18 @@
</PropertyGroup>
<ItemGroup>
<Content Include="Alphas\ForexCalendarAlpha.py" />
<Content Include="Alphas\GasAndCrudeOilEnergyCorrelationAlpha.py" />
<Content Include="Alphas\GlobalEquityMeanReversionIBSAlpha.py" />
<Content Include="Alphas\IntradayReversalCurrencyMarketsAlpha.py" />
<Content Include="Alphas\GreenblattMagicFormulaAlpha.py" />
<Content Include="Alphas\MeanReversionLunchBreakAlpha.py" />
<Content Include="Alphas\PriceGapMeanReversionAlpha.py" />
<Content Include="Alphas\SykesShortMicroCapAlpha.py" />
<Content Include="Alphas\RebalancingLeveragedETFAlpha.py" />
<Content Include="Alphas\TriangleExchangeRateArbitrageAlpha.py" />
<Content Include="Alphas\ShareClassMeanReversionAlpha.py" />
<Content Include="Alphas\TripleLeverageETFPairVolatilityDecayAlpha.py" />
<Content Include="Alphas\VIXDualThrustAlpha.py" />
<Content Include="BasicSetAccountCurrencyAlgorithm.py" />
<Content Include="BasicTemplateFuturesFrameworkAlgorithm.py" />
<Content Include="BasicTemplateOptionsFrameworkAlgorithm.py" />
@@ -160,7 +167,7 @@
<None Include="Benchmarks\HistoryRequestBenchmark.py" />
<None Include="Benchmarks\CoarseFineUniverseSelectionBenchmark.py" />
<None Include="Benchmarks\IndicatorRibbonBenchmark.py" />
<None Include="Benchmarks\ScheduleEventsBenchmark.py" />
<None Include="Benchmarks\ScheduledEventsBenchmark.py" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Algorithm\QuantConnect.Algorithm.csproj">
@@ -199,22 +206,22 @@
<Choose>
<When Condition="$(IsWindows) AND '$(ForceLinuxBuild)' != 'true'">
<ItemGroup>
<Reference Include="Python.Runtime, Version=1.0.5.15, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\QuantConnect.pythonnet.1.0.5.15\lib\win\Python.Runtime.dll</HintPath>
<Reference Include="Python.Runtime, Version=1.0.5.17, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\QuantConnect.pythonnet.1.0.5.17\lib\win\Python.Runtime.dll</HintPath>
</Reference>
</ItemGroup>
</When>
<When Condition="$(IsLinux) OR '$(ForceLinuxBuild)' == 'true'">
<ItemGroup>
<Reference Include="Python.Runtime, Version=1.0.5.15, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\QuantConnect.pythonnet.1.0.5.15\lib\linux\Python.Runtime.dll</HintPath>
<Reference Include="Python.Runtime, Version=1.0.5.17, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\QuantConnect.pythonnet.1.0.5.17\lib\linux\Python.Runtime.dll</HintPath>
</Reference>
</ItemGroup>
</When>
<When Condition="$(IsOSX) AND '$(ForceLinuxBuild)' != 'true'">
<ItemGroup>
<Reference Include="Python.Runtime, Version=1.0.5.15, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\QuantConnect.pythonnet.1.0.5.15\lib\osx\Python.Runtime.dll</HintPath>
<Reference Include="Python.Runtime, Version=1.0.5.17, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\QuantConnect.pythonnet.1.0.5.17\lib\osx\Python.Runtime.dll</HintPath>
</Reference>
</ItemGroup>
</When>
@@ -228,12 +235,12 @@
./build.sh
</PostBuildEvent>
</PropertyGroup>
<Import Project="..\packages\QuantConnect.pythonnet.1.0.5.15\build\QuantConnect.pythonnet.targets" Condition="Exists('..\packages\QuantConnect.pythonnet.1.0.5.15\build\QuantConnect.pythonnet.targets')" />
<Import Project="..\packages\QuantConnect.pythonnet.1.0.5.17\build\QuantConnect.pythonnet.targets" Condition="Exists('..\packages\QuantConnect.pythonnet.1.0.5.17\build\QuantConnect.pythonnet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\QuantConnect.pythonnet.1.0.5.15\build\QuantConnect.pythonnet.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\QuantConnect.pythonnet.1.0.5.15\build\QuantConnect.pythonnet.targets'))" />
<Error Condition="!Exists('..\packages\QuantConnect.pythonnet.1.0.5.17\build\QuantConnect.pythonnet.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\QuantConnect.pythonnet.1.0.5.17\build\QuantConnect.pythonnet.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
@@ -23,7 +23,6 @@ from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
import numpy as np
import decimal as d
from datetime import timedelta, datetime
### <summary>
+1 -1
View File
@@ -47,7 +47,7 @@ class RollingWindowAlgorithm(QCAlgorithm):
# Creates an indicator and adds to a rolling window when it is updated
self.sma = self.SMA("SPY", 5)
self.Updated += self.SmaUpdated
self.sma.Updated += self.SmaUpdated
self.smaWin = RollingWindow[IndicatorDataPoint](5)
+12 -5
View File
@@ -54,6 +54,9 @@ class ScheduledEventsAlgorithm(QCAlgorithm):
# time rule here tells it to fire 10 minutes before SPY's market close
self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 10), self.EveryDayAfterMarketClose)
# schedule an event to fire on a single day of the week
self.Schedule.On(self.DateRules.Every(DayOfWeek.Wednesday), self.TimeRules.At(12, 0), self.EveryWedAtNoon)
# schedule an event to fire on certain days of the week
self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Friday), self.TimeRules.At(12, 0), self.EveryMonFriAtNoon)
@@ -74,25 +77,29 @@ class ScheduledEventsAlgorithm(QCAlgorithm):
def SpecificTime(self):
self.Log("SpecificTime: Fired at : {0}".format(self.Time))
self.Log(f"SpecificTime: Fired at : {self.Time}")
def EveryDayAfterMarketOpen(self):
self.Log("EveryDay.SPY 10 min after open: Fired at: {0}".format(self.Time))
self.Log(f"EveryDay.SPY 10 min after open: Fired at: {self.Time}")
def EveryDayAfterMarketClose(self):
self.Log("EveryDay.SPY 10 min before close: Fired at: {0}".format(self.Time))
self.Log(f"EveryDay.SPY 10 min before close: Fired at: {self.Time}")
def EveryWedAtNoon(self):
self.Log(f"Wed at 12pm: Fired at: {self.Time}")
def EveryMonFriAtNoon(self):
self.Log("Mon/Fri at 12pm: Fired at: {0}".format(self.Time))
self.Log(f"Mon/Fri at 12pm: Fired at: {self.Time}")
def LiquidateUnrealizedLosses(self):
''' if we have over 1000 dollars in unrealized losses, liquidate'''
if self.Portfolio.TotalUnrealizedProfit < -1000:
self.Log("Liquidated due to unrealized losses at: {0}".format(self.Time))
self.Log(f"Liquidated due to unrealized losses at: {self.Time}")
self.Liquidate()
@@ -25,7 +25,6 @@ from QuantConnect.Data import *
from QuantConnect.Orders import *
from QuantConnect.Securities import *
from QuantConnect.Util import *
import decimal as d
from math import copysign
from datetime import datetime
@@ -79,11 +78,11 @@ class UpdateOrderRegressionAlgorithm(QCAlgorithm):
self.last_month = self.Time.month
self.Log("ORDER TYPE:: {0}".format(orderType))
isLong = self.quantity > 0
stopPrice = d.Decimal(1 + self.stop_percentage)*data["SPY"].High if isLong else d.Decimal(1 - self.stop_percentage)*data["SPY"].Low
limitPrice = d.Decimal(1 - self.limit_percentage)*stopPrice if isLong else d.Decimal(1 + self.limit_percentage)*stopPrice
stopPrice = (1 + self.stop_percentage)*data["SPY"].High if isLong else (1 - self.stop_percentage)*data["SPY"].Low
limitPrice = (1 - self.limit_percentage)*stopPrice if isLong else (1 + self.limit_percentage)*stopPrice
if orderType == OrderType.Limit:
limitPrice = d.Decimal(1 + self.limit_percentage)*data["SPY"].High if not isLong else d.Decimal(1 - self.limit_percentage)*data["SPY"].Low
limitPrice = (1 + self.limit_percentage)*data["SPY"].High if not isLong else (1 - self.limit_percentage)*data["SPY"].Low
request = SubmitOrderRequest(orderType, self.security.Symbol.SecurityType, "SPY", self.quantity, stopPrice, limitPrice, self.UtcTime, str(orderType))
ticket = self.Transactions.AddOrder(request)
@@ -96,7 +95,7 @@ class UpdateOrderRegressionAlgorithm(QCAlgorithm):
if len(ticket.UpdateRequests) == 0 and ticket.Status is not OrderStatus.Filled:
self.Log("TICKET:: {0}".format(ticket))
updateOrderFields = UpdateOrderFields()
updateOrderFields.Quantity = ticket.Quantity + d.Decimal(copysign(self.delta_quantity, self.quantity))
updateOrderFields.Quantity = ticket.Quantity + copysign(self.delta_quantity, self.quantity)
updateOrderFields.Tag = "Change quantity: {0}".format(self.Time)
ticket.Update(updateOrderFields)
@@ -104,8 +103,8 @@ class UpdateOrderRegressionAlgorithm(QCAlgorithm):
if len(ticket.UpdateRequests) == 1 and ticket.Status is not OrderStatus.Filled:
self.Log("TICKET:: {0}".format(ticket))
updateOrderFields = UpdateOrderFields()
updateOrderFields.LimitPrice = self.security.Price*d.Decimal(1 - copysign(self.limit_percentage_delta, ticket.Quantity))
updateOrderFields.StopPrice = self.security.Price*d.Decimal(1 + copysign(self.stop_percentage_delta, ticket.Quantity))
updateOrderFields.LimitPrice = self.security.Price*(1 - copysign(self.limit_percentage_delta, ticket.Quantity))
updateOrderFields.StopPrice = self.security.Price*(1 + copysign(self.stop_percentage_delta, ticket.Quantity))
updateOrderFields.Tag = "Change prices: {0}".format(self.Time)
ticket.Update(updateOrderFields)
else:
+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="QuantConnect.pythonnet" version="1.0.5.15" targetFramework="net452" />
<package id="QuantConnect.pythonnet" version="1.0.5.17" targetFramework="net452" />
</packages>