Merge branch 'master' into price_gap_alpha
This commit is contained in:
@@ -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. 90–91.
|
||||
#
|
||||
# <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
|
||||
+63
-64
@@ -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)
|
||||
@@ -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.
|
||||
|
||||
+5
-7
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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,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>
|
||||
Reference in New Issue
Block a user