This algorithm is roughly based on 2 books: Benjamin Graham's "The Intelligent Investor" and Patrick O'Shaughnessy's "Millenial Money". I am hoping to improve it in the nearest future by telling it to sell only in the case if the Sell - Buy of any given stock is positive, by allocating a different weight to each stock based on the market cap and by hopefully including: some of the more complicated HFT strategies and sentiment analysis.
Clone Algorithm
79
Backtest from
to
with
initial capital
Cumulative performance:
Algorithm
Benchmark
Custom data:
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns | 1 Month | 3 Month | 6 Month | 12 Month |
Alpha | 1 Month | 3 Month | 6 Month | 12 Month |
Beta | 1 Month | 3 Month | 6 Month | 12 Month |
Sharpe | 1 Month | 3 Month | 6 Month | 12 Month |
Sortino | 1 Month | 3 Month | 6 Month | 12 Month |
Volatility | 1 Month | 3 Month | 6 Month | 12 Month |
Max Drawdown | 1 Month | 3 Month | 6 Month | 12 Month |
""" This Algorithm takes ideas from Benjamin Graham's Book ("The Intelligent Investor" and from Patrick O'Shaughnessy's book ("Millennial Money"). Although their ideas are similar there are some changes to the screening process. """ import pandas as pd import numpy as np def initialize(context): ### This instructions are here, because I am using Robinhood (famous for 0 fees and no shorting ability) set_long_only() set_commission(commission.PerTrade(cost=0)) ### For Fundamentals Screening context.max_num_stocks = 50 ### Start the countdown (in days) context.days = 0 ### How long is the period (in days), for buy/sell frequency, !!!SUBJECT TO CHANGE!!! context.periods_in_days = 100 schedule_function(compute_and_rebalance, date_rules.every_day(), time_rules.market_open(minutes=30)) def period_passed(context): ### This will tell if the period has passed and if it is time to buy/sell return context.days % context.periods_in_days == 0 def before_trading_start(context, data): context.days += 1 if not period_passed(context): return screening(context) context.security_list = list(context.fundamental_df.columns.values) def screening(context): ### This is where screening (the most important part takes place) fundamental_df = get_fundamentals( query( fundamentals.share_class_reference.is_primary_share, fundamentals.cash_flow_statement.financing_cash_flow, fundamentals.valuation.market_cap, fundamentals.valuation_ratios.pe_ratio, fundamentals.valuation_ratios.pb_ratio, fundamentals.valuation_ratios.dividend_yield, fundamentals.income_statement.research_and_development, fundamentals.income_statement.operating_income, fundamentals.income_statement.net_income, fundamentals.balance_sheet.cash_and_cash_equivalents, ) .filter(fundamentals.share_class_reference.is_primary_share == True) .filter(fundamentals.valuation.market_cap > 10000000) .filter(fundamentals.valuation_ratios.pe_ratio < 11) .filter(fundamentals.valuation_ratios.pb_ratio < 1.6) .filter(fundamentals.income_statement.research_and_development > 0) .filter(fundamentals.valuation_ratios.dividend_yield > 0.015) .filter(fundamentals.valuation.shares_outstanding > 0) .filter(fundamentals.balance_sheet.cash_and_cash_equivalents > 0) .filter( fundamentals.income_statement.net_income > 0) .limit(context.max_num_stocks) ) ### Updating context context.stocks = [stock for stock in fundamental_df] context.fundamental_df = fundamental_df def rebalance(context, data): ### Sell all shares before buying new ones for stock in context.portfolio.positions: if stock in context.fundamental_df: if data.can_trade(stock): ### Add an instruction which only allows to sell if you sell higher then you bought order_target_percent(stock, 0) ### Leave a 2% cash reserve. weight = 0.98/len(context.stocks) ### buy all stocks equally, (To change in the future) for stock in context.stocks: if data.can_trade(stock): order_target_percent(stock, weight) def compute_and_rebalance(context, data): if not period_passed(context): return rebalance(context, data)