Stock Screening
-
Use the link below to go the original post
Click here to see the full blog post
-
How do you stop the output printing:
"""- Datas:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Data0:"""
for each data source added? -
You cannot with the standard
WriterFile
which is the one creating the output.You can if you subclass it, check the sources, and create your own output.
-
Thank you. How do I subclass it, check the sources and create a different output?
-
There is no other way.
In any case the expected (even if small) API of the
Writer
should have a small documentation page to ease up subclassing. -
Thank you for this example. can you please complete it by using this screener as input to a strategy. for instance to be long under and short the long list and close the trades if they go out of the list. thx a lot
-
See this reddit post: Reddit - The Conservative Formula in Python: Quantitative Investing made Easy
The code
class St(bt.Strategy): params = dict( rperiod=1, # period for the returns calculation, default 1 period vperiod=36, # lookback period for volatility - default 36 periods mperiod=12, # lookback period for momentum - default 12 periods torank=100, # number of stocks to rank as top reserve=0.05 # 5% reserve capital ) def __init__(self): # Return, volatility and momentum rets = [bt.ind.PctChange(d, period=self.p.rperiod) for d in self.datas] vols = [bt.ind.StdDev(ret, period=self.p.vperiod) for ret in rets] moms = [bt.ind.ROC(d, period=self.p.mperiod) for d in self.datas] # simple rank formula: (momentum * net payout) / volatility # The highest ranked: low vol, large momentum, large payout self.ranks = [d.npy * m / v for d, v, m in zip(self.datas, vols, moms)] # allocation perc pro stock # reserve kept to make sure orders are not rejected due to # margin. Prices are calculated when known (close), but orders can only # be executed next day (opening price). Price can gap upwards self.perctarget = (100.0 - self.p.reserve) % self.p.torank def next(self): # get the ranks sorted for each iteration in a list ranks = sorted( ((self.datas[i], rank[0]) for i, rank in enumerate(self.ranks)), key=lambda x: x[1], # use rank (elem 1 in the tuple) to sort reverse=True, # highest ranked 1st ... please ) # Put top 100 in ordereddict with data as key to test for presence r100 = collections.OrderedDict(ranks[:self.p.torank]) # Remove those no longer Top 100, prepare quick lookup dict positions = {pos: pos.data for pos in self.getpositions() if pos} for pos, data in positions.items(): if data not in r100: # open and no rank100 ... close self.order_target_percent(data, target=0.0) # Add the newcomers to the Top 100, prepare easy reverse lookup revpositions = {data: pos for pos, data in positions.items()} for data in (d for d in r100 if d not in revpositions): self.order_target_percent(data, target=self.perctarget)
-
@backtrader You are awesome!! many thanks
-
@backtrader Hi, I've tryed to test your code but unfortunatly it didn't work properly as the compiler do not reconignize "pos.data" from this line "{pos: pos.data for pos in self.getpositions() if pos}" and also i suspect this line too "self.order_target_percent(data, target=self.perctarget)" the self.order_target percent part. Can you please share the full code that works for you?
-
from backtrader.feeds import PandasData
class PycaishenData(PandasData):
# Add a 'pe' line to the inherited ones from the base class lines = ('turnover','mkt_cap') # openinterest in GenericCSVData has index 7 ... add 1 # add the parameter to the parameters inherited from the base class params = (('turnover', -1),('mkt_cap',-1))
class StAmine(bt.Strategy):
params = dict(
rperiod=1, # period for the returns calculation, default 1 period
vperiod=36, # lookback period for volatility - default 36 periods
mperiod=12, # lookback period for momentum - default 12 periods
torank=10, # number of stocks to rank as top
reserve=0.05 # 5% reserve capital
)def __init__(self): # The highest ranked: mkt_cap self.ranks = [bt.ind.movav(d.mkt_cap,period = 1) for d in self.datas] # allocation perc pro stock # reserve kept to make sure orders are not rejected due to # margin. Prices are calculated when known (close), but orders can only # be executed next day (opening price). Price can gap upwards self.perctarget = (100.0 - self.p.reserve) % self.p.torank def next(self): # get the ranks sorted for each iteration in a list ranks = sorted( ((self.datas[i], rank[0]) for i, rank in enumerate(self.ranks)), key=lambda x: x[1], # use rank (elem 1 in the tuple) to sort reverse=True, # highest ranked 1st ... please ) # Put top 100 in ordereddict with data as key to test for presence r100 = collections.OrderedDict(ranks[:self.p.torank]) # Remove those no longer Top 100, prepare quick lookup dict positions = {pos: pos.data for pos in self.getpositions().values() if pos} for pos, data in positions.items(): if data not in r100: # open and no rank100 ... close self.order_target_percent(data, target=0.0) # Add the newcomers to the Top 100, prepare easy reverse lookup revpositions = {data: pos for pos, data in positions.items()} for data in (d for d in r100 if d not in revpositions): self.order_target_percent(data, target=self.perctarget)
def run(tickers, datas,strategy = StAmine,plotdetails= True,writedetail = False):
cerebro = bt.Cerebro() print ('Starting Portfolio Value: %.2f ' % cerebro.broker.getvalue()) cerebro.addstrategy(strategy) for ticker, data in zip(tickers , datas): dt = PycaishenData(dataname=data) if plotdetails == False: dt.plotinfo.plot = False cerebro.adddata(dt,ticker) cerebro.broker.set_fundmode(True) cerebro.broker.set_fundstartval(10.0) # the default is 100 cerebro.broker.setcommission(commission=0.0025) # Add the Analyzers cerebro.addanalyzer(btanalyser.SQN) cerebro.addanalyzer(btanalyser.AnnualReturn) cerebro.addanalyzer(btanalyser.SharpeRatio) cerebro.broker.setcash(100000.0) cerebro.addanalyzer(btanalyser.TradeAnalyzer) if writedetail: cerebro.addwriter(bt.WriterFile, csv=True, rounding=4) cerebro.run() cerebro.plot() print ('Final portfolio value: %.2f' % cerebro.broker.getvalue())
run(tickers, datas,strategy = StAmine,plotdetails= False,writedetail = False)
the code seems to do nothing!!
-
@spyamine said in Stock Screening:
Hi, I've tryed to test your code but unfortunatly it didn't work properly as the compiler do not reconignize "pos.data" from this line "{pos: pos.data for pos in self.getpositions() if pos}" and also i suspect this line too "self.order_target_percent(data, target=self.perctarget)" the self.order_target percent part. Can you please share the full code that works for you?
It is a hand-crafted snippet, giving an indication and orientation as to how a proposed algorithm could be implemented.