Young quant in need of assistance

Hello, I am an aspiring quant (I'm eighteen years old) with limited Python knowledge. I am struggling to make my system do certain things and behave as expected.

Note: My system uses moving average crossovers as buy and sell triggers. Should be pretty simple, but I am having the following problems:

1) Logging the price at which my system buys a stock. (Useful for future debugging I hope.) Also logging (price x number of shares purchased) (does Quantopian call this amount?) would be helpful.
2) Preventing my system from using leverage! Included with this, I would like to log my remaining cash at the end of each transaction.
3) Using the built-in portfolio object instead of the custom dictionary I created. (portfol[])
4) Making my code more user friendly/professional/efficient for future expansion. Also, removing useless code.

If anyone notices any major flaws in my logic/approach/code, please notify me.

Note: I realize that this code is extremely primitive, as I am trying to grasp the basics of Quantopain by constructing a simple algorithm and then expanding from there. Any other general tips are would be much appreciated. Thanks!

def initialize(context):
set_symbol_lookup_date('2012-01-01')
set_universe(universe.DollarVolumeUniverse(floor_percentile=99.0, ceiling_percentile=100.0))

context.max_notional = 10000.1
context.min_notional = -10000.0
context.init_margin=1.00 #Set initial margin requirement
context.pct_invested_threshold = 0.95
def handle_data(context, data):
for stock in data:
current_price = data[stock].price
moving_avg_20 = data[stock].mavg(20)
moving_avg_50 = data[stock].mavg(50)
moving_avg_200 = data[stock].mavg(200)

mymoney = context.portfolio.cash
if moving_avg_50 > moving_avg_200 and mymoney > current_price and mymoney > 0 and buying_power > 0:
cash = context.portfolio.cash
global portfol
portfol = []
portfol.append(stock)
# SELLING:
if moving_avg_50 < moving_avg_200 and stock in portfol:
order_target(stock, 0)
log.info("Selling %s on %s" % ((stock.symbol), (tradeday.strftime('%m/%d/%y'))))
portfol.remove(stock)
10 responses

Hey Young Quant. Love to see younger people taking part in Quantopian. I am also new and I'm having similar issues with my algos. Any help would be appreciated. Sorry if my English is bad.

Awesome! Glad to see I'm not the only one struggling with these issues.

Hey Young,
I'm new too, 19 years old, so take this with a grain of salt...

1) You can use the record function to track leverage. This will graph your leverage for you " record('Leverage', context.account.leverage)"

2) I think you're over leveraging because for each stock that meets your buying conditions you allocate 10% of portfolio value to it. Often times there are 40 or 50 of these stocks that you end up buying, all with 10% of your portfolio value. This is why your leverage often stays at 4 or 5, giving you those massive performance swings.

Also, Buying power is set to infinity in the backtests, so buying_power > 0 is always true. As to why cash > 0 seems to always be true I'll have to investigate. I'd guess that when it is set, it uses the initial value it was set to each time, without updating. But I'm not sure. I'll get back to this.

It looks like cash isn't updating until the function ends. This is the code I used to test it.

def initialize(context):
context.stocks = symbols('SPY', 'TQQQ')
#Only here to run once a day for debugging
schedule_function(day, date_rules.every_day(), time_rules.market_open(minutes=1), half_days=True)

def day(context, data):
cash = context.portfolio.cash  #The amount of cash
print "Initial cash is {cash} ".format(cash = cash)
for stock in context.stocks:
print "Cash is {cash} before ordering {sec} ".format(sec = stock.symbol, cash = cash)
order_target_percent(stock, 1.0)
print "Cash is {cash} after ordering {sec} ".format(sec = stock.symbol, cash = cash)
print ""  #New line to make it readable

def handle_data(context, data):
pass

The log output is:

2015-01-05PRINTInitial cash is 1000000.0
2015-01-05PRINTCash is 1000000.0 before ordering SPY
2015-01-05PRINTCash is 1000000.0 after ordering SPY
2015-01-05PRINTCash is 1000000.0 before ordering TQQQ
2015-01-05PRINTCash is 1000000.0 after ordering TQQQ
2015-01-05PRINT
2015-01-06PRINTInitial cash is -1001417.03002
2015-01-06PRINTCash is -1001417.03002 before ordering SPY
2015-01-06PRINTCash is -1001417.03002 after ordering SPY
2015-01-06PRINTCash is -1001417.03002 before ordering TQQQ
2015-01-06PRINTCash is -1001417.03002 after ordering TQQQ

Yes, that's right, all of the variables and positions are updated at the end of handle_data(). They are not updated in the middle of a call. YQ for your other questions.

Logging the price at which my system buys a stock

If you do "data[stock].price" this will give you the price when your order was submitted. T get the full price, take a look at this thread: https://www.quantopian.com/posts/fill-price-of-market-orders. I'd also recommend to use the debugger to understand your code and order placements.

Preventing my system from using leverage

You're on the right track in your code by using "order_target". This will minimize the leverage in your algo. One of the rough edges of this function is it doesn't consider the status of open orders when making it's calculations. It only considers filled orders for the target. I would add this line to handle_data():

if get_open_orders():
log.info("There are open orders, exiting")
return

Using the built-in portfolio object instead of the custom dictionary I created

You can use "context.portfolio.positions" https://www.quantopian.com/help#api-portfolio

And in case you haven't seen it yet, take a look at the tutorial videos. Good luck!

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Thank you Calvin and Alisa for your replies.

Calvin, the leverage recording works beautifully, thanks.

As far as order_target_percent, shouldn't the system only order 10% worth of the remaining portfolio cash? In that case, I don't understand how the system would go into debt since with every purchase there is less cash available for spending, and the 10% amount for buying a new stock would continue decrease, eventually reaching zero. Alisa says that the system is still incurring debt because the function "doesn't consider the status of open orders." I added her code to fix this, but the algo is still going into debt.

Calvin, your cash testing was very interesting. I recall doing some similar testing and getting the same (seemingly random) negative number after the cash updated. Any ideas as to why the cash is going from 1000000.0 to -1001417.03002? So far I have still been unable to use the cash function properly. Alisa, how do list (or cycle through them in a for loop or something similar) the stocks that are in context.portfolio.positions?

Here is my updated code. I currently have a strange system of logging to avoid the limits that Quantopian has. If anyone has a better way, please tell me. Anyways, on line 44, I attempt to log the price at which the stock was bought, but my log outputs show 1000000.0 for every purchased stock.

def initialize(context):
set_symbol_lookup_date('2012-01-01')
set_universe(universe.DollarVolumeUniverse(floor_percentile=99.0, ceiling_percentile=100.0))

context.max_notional = 10000.1
context.min_notional = -10000.0
context.init_margin=1.00 #Set initial margin requirement
context.pct_invested_threshold = 0.95

def handle_data(context, data):
if get_open_orders():
log.info("There are open orders, exiting")
return
record('Leverage', context.account.leverage)
global portfol
portfol = []
#portfol = context.portfolio.positions
for stock in data:
current_price = data[stock].price
moving_avg_20 = data[stock].mavg(20)
moving_avg_50 = data[stock].mavg(50)
moving_avg_200 = data[stock].mavg(200)

mymoney = context.portfolio.cash
if moving_avg_50 > moving_avg_200 and mymoney > current_price and mymoney > 0 and buying_power > 0:
cash = context.portfolio.cash
else:
portfol.append(stock)
#portfol.update(stock)

# SELLING:
if moving_avg_50 < moving_avg_200 and stock in portfol:
order_target(stock, 0)
log.info("Selling %s on %s" % ((stock.symbol), (tradeday.strftime('%m/%d/%y'))))
portfol.remove(stock)
log.info(portfol)

Thanks again for the responses thus far!

Young Q., Give this a try. The key is to use determine new entries and then combine them with existing positions. Then rebalance using the combined total.

10
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
Leverage = .95

def initialize(context):
set_symbol_lookup_date('2012-01-01')
set_universe(universe.DollarVolumeUniverse(floor_percentile=99.0, ceiling_percentile=100.0))

schedule_function(HandleExits)
schedule_function(HandleEntries)

def handle_data(context, data):
positions = context.portfolio.positions
record(Leverage      = context.account.leverage)
record(OpenPositions = sum([1 for sid in positions if positions[sid].amount > 0]))

def HandleEntries(context, data):
positions = context.portfolio.positions
openLongPositions = [sid for sid in positions if positions[sid].amount > 0]

eligible = []
for stock in data:
current_price  = data[stock].price
moving_avg_20  = data[stock].mavg(20)
moving_avg_50  = data[stock].mavg(50)
moving_avg_200 = data[stock].mavg(200)

if moving_avg_50 > moving_avg_200 and moving_avg_20 > current_price:
if (stock not in openLongPositions and not get_open_orders(stock)):
eligible.append(stock)

eligible = eligible + openLongPositions
eligibleCount = float(len(eligible))
for stock in eligible:
order_target_percent(stock, (1.0 / eligibleCount) * Leverage)

def HandleExits(context, data):
for stock in data:
moving_avg_50 = data[stock].mavg(50)
moving_avg_200 = data[stock].mavg(200)
if (moving_avg_50 < moving_avg_200):
order_target_percent(stock, 0.0)

There was a runtime error.

@Alisa, come on, get your guys to bring back the "record()" legend, would ya?

Thanks Market Tech for the useful code. I am wondering, however, why backtesting your algo is much slower than backtesting my algos. Is there a way to increase efficiency? Also, what would you or anyone else recommend for logging the date, amount, and ticker for every transaction without hitting the logging limit?

Yeah the slowness of Market Tech's code was weird. Yes I agree. Code for logging with the post above would be helpful