Hi everyone,
I've been a Quantopian user for the past years. Now I'm currently testing QuantConnect.
The main features that I liked there and I think would be a big plus for QuantConnect:
- The ability to select easily through all the universe (similar pipelines)
- The ability to debug backtesting and run commands at the breakpoints
- The ability to debug locally a backtesting (with zipline, I was able to debug Factor Calculations or other locally)
- At EOD, I want to go through all the universe and calculate the average daily volume for the past 52 w, the high of the past 52w and the resistance on the last 3 years => Select only a few securities that meet specific conditions with these stocks
- At every minute, get the price, the total daily volume then compare and select securities that verify specific conditions with this information (not in the below code)
from clr import AddReference
AddReference("System.Core")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Orders import OrderStatus
from QuantConnect.Orders.Fees import InteractiveBrokersFeeModel
LAST_TRADED_PRICE_MIN = 0.85
LAST_TRADED_PRICE_MAX = 10
WEEKS = 52
DAILY_VOLUME_MIN = 3000000
DAILY_VOLUME_MAX = 1000000000
MIN_DAILY_RETURNS = 8
MAX_DAILY_RETURNS = 100
WEEK_HIGH_MIN_FACTOR = 0.01
WEEK_HIGH_MAX_FACTOR = 0.07
WEEKS_PREVIOUS_RESISTANCE = 156
WEEKS_PREVIOUS_RESISTANCE_FACTOR = 0.23
TARGET_PERCENTAGE = 0.5
LOSS_THRESHOLD = .07
PROFIT_THRESHOLD = -.03
class Factors:
def __init__(self, weeks_high=52, weeks_resistance=156):
self.days_high = (weeks_high + 1) * 5
self.days_resistance = (weeks_resistance + 1) * 5
def process(self, element):
"""
:param element: dict(str, pd.DataFrame)
:type element:
:return:
:rtype:
"""
element['week_high'] = element['high'].rolling(
window=self.days_high).max()
element['dollar_volume'] = element['volume'] * element['close']
element['average_daily_volume'] = element['dollar_volume'].rolling(
window=self.days_high).mean()
element['previous_resistance'] = element['high'].rolling(
window=self.days_resistance).max()
element['is_tradable'] = element['previous_resistance'] >= (
1 + WEEKS_PREVIOUS_RESISTANCE_FACTOR) * element['week_high']
element.dropna(inplace=True)
return element[element['is_tradable']]
class RawPricesCoarseUniverseAlgorithm(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.'''
# what resolution should the data *added* to the universe be?
self.UniverseSettings.Resolution = Resolution.Daily
self.SetStartDate(2020,11,1) #Set Start Date
self.SetEndDate(2020,12,1) #Set End Date
self.SetCash(10000) #Set Strategy Cash
# Set the security initializer with the characteristics defined in CustomSecurityInitializer
self.SetSecurityInitializer(self.CustomSecurityInitializer)
# this add universe method accepts a single para&é@a meter that is a function that
# accepts an IEnumerable<CoarseFundamental> and returns IEnumerable<Symbol>
self.AddUniverse(self.CoarseSelectionFunction)
# Taking profit
self.take_profit_active = True
self.profit_threshold = .07
self.profit_logging = True
# Stop Loss
self.stoploss_active = True
self.loss_threshold = -.03
self.stoploss_logging = True
def CustomSecurityInitializer(self, security):
'''Initialize the security with raw prices and zero fees
Args:
security: Security which characteristics we want to change'''
security.SetFeeModel(InteractiveBrokersFeeModel())
# sort the data by daily dollar volume and take the top 'NumberOfSymbols'
def CoarseSelectionFunction(self, coarse):
df = self.History([s.Symbol for s in coarse], (WEEKS_PREVIOUS_RESISTANCE + 1) * 5, Resolution.Daily)
self.Log(f"Processing Data")
self.data = Factors(weeks_high=WEEKS, weeks_resistance=WEEKS_PREVIOUS_RESISTANCE).process(df)
self.Log(f"Total symbols found {len(self.data)}")
x = len(self.data)
return [s for s in coarse if str(s) in self.data]