Choosing when, and how to sell

Knowing when to sell is one of the problems I struggle with as a trader, both in equities and crypto markets. In the past, I’ve relied on what the Motley Fool has referred to as a ‘buy and hold forever’ strategy, and it’s worked out well for me with some of the bigger tech stocks. As someone who’s been focusing more on shorter time frames lately, I’ve been having less success. And after watching my crypto portfolio break six figures in the winter of 2017 before crashing almost ninety percent, I’ve been trying to find a way to ensure that I’m able to actually take some profits when my positions start taking those parabolic runs.

One of the interesting metrics around the USD price of Bitcoin is the Mayer Multiple, which is the multiple of the current BTC price over the 200-day moving average. Trace Mayer determined that, historically speaking, the best long-term strategy was to accumulate BTC when when the Mayer Multiple was under 2.4. For comparison, the last time we hit that level was late June of this year when BTC hit $14K. Now I have traditionally been one to dollar-cost average into BTC, weekly, but I had to stop my contributions for a variety of market and personal reasons, but one plan I have been thinking about is to sell a large share of my position when the MM hits 2.88. This is a number I cam up with just by looking at the charts, and is currently about $26,200.

So I was really interested by this strategy put together by former BlackRock portfolio manager Vishal Karir, on how to take profits before the next bitcoin recession. I’m not going to rehash the entire piece here, suffice to say it sets a static accumulation target, buys when the asset value is below this target, and sells when it’s above it. I wanted to do some backtesting with some of my assets and see what I came up with. So I wrote up the following code in a Google Collab doc so I could start playing around with it.

Instead of looking at BTC directly, I wanted to start by looking at the Grayscale BTC ETF, GBTC, so for this block we’re using Pandas wonderful datareader to pull quotes from AlphaVantage.

import os
from datetime import datetime
import pandas_datareader.data as web

!pip install ipywidgets
import ipywidgets as widgets
from ipywidgets import interact, interact_manual

os.environ['ALPHAVANTAGE_API_KEY'] = 'my_key'

f = ""

time_series = [
    ("Intraday Time Series", "av-intraday"),
    ("Daily Time Series", "av-daily"),
    ("Daily Time Series (Adjusted)", "av-daily-adjusted"), 
    ("Weekly Time Series", "av-weekly"), 
    ("Weekly Time Series (Adjusted)", "av-weekly-adjusted"),
    ("Monthly Time Series", "av-monthly"),
    ("Monthly Time Series (Adjusted)", "av-monthly-adjusted")
]  
     

def get_asset_data (ticker, time_frame="av-weekly", start_date="2017-01-01", end_date="2019-09-30"):
  global f
  f = web.DataReader(ticker,
                     time_frame, 
                     start = parse(start_date), 
                     end = parse(end_date))
  return f

interact_manual(get_asset_data, ticker="", time_frame=time_series)

We’re using f as a global for our dataframe. It stores the stock data. We’re also using ipywidgets to allow us to easily change parameters for the data we want to run against.


The next cell allows us to pass this previous dataframe to our backtest function. I wanted to play with various parameters such as the amount of capital available, the max contribution, and the ratio of max contributions to max sell amount.

def run_karir_target(price_data, capital, contribute=100, sell_factor=2):

  def get_asset_value(price):
    return (shares * price)
  
  def buy(amount, price):
    
    nonlocal shares, cash
    if amount > 0:
      if amount > contribute:
        amount = contribute
      action = "BUY"
    else:
      if amount < -sell:
        amount = -sell
      action = "SELL"


    num_shares = amount/price
    print("{} {} shares for {}".format(action, num_shares, amount))

    cash -= amount
    shares += num_shares

    
  f = price_data
  cash = capital
  contribute=contribute
  sell_factor = sell_factor
  
  shares = 0
  sell = sell_factor * contribute
  week = 1

  for i, j in f.iterrows(): 
    if cash < 0:
      print ("Out of cash!")
      break
    price = j['open']
    print("Week {}: {}".format(week,i))

    target = week * contribute
    value = get_asset_value(price)
    print("Target: {} Asset value = {}".format(target,value))

    difference = target - value
    # 0 - 500 = -500

    buy(difference, price)
    new_total = get_asset_value(price)
    total = cash + new_total

    print ("Total: {}, Cash: {}, Shares: {}, Asset Value: {}".format(total, cash, shares, new_total))  
    print()
    week += 1

Now there’s a lot here I will do later to clean up this code, making the params available via a widget as I did for the first function, but for now it works just fine. Here’s a test run with $100 contributed weekly from just after the beginning of the BTC bear market till now.

Week 1 and 2 of our backtest
The ‘bottom’.
We’re not including the entire run, but here’s where we end up.

So, not bad on our hypothetical run. That’s a gain of almost $4700 off of $3769 invested, or a 24% return. Now we’re cherry-picking, or course. At the bottom of the market, we would have had over $7K deployed at a break even. But Karir’s strategy opens up a whole slew of possibilities, and what may be a good rule of thumb for scaling out of positions. Since I’ve been able to get this package working, I’ve been looking at other investments that I’ve made in equities markets, and am starting to form some hypotheses that may help guide best practices for both entries and exits.

My next step, after cleaning up this code a bit, is to figure out a way to run some regression tests on the sell multiple. I think a dynamic variable may actually be more helpful in instances where the asset goes on a parabolic run. But the point here is that I have a framework that I can test my assumptions against.

It shouldn’t be too hard also to integrate Karir’s strategy for accumulation of BTC, as well as altcoin pairings as well. It’s an exciting strategy for investment, and one that can be automated via exchange and broker APIs. There may also be some variations that we can deploy, using this kind of targeted portfolio value as a way to layer limit orders. For this simulation we simply used the open price of the time period, but we could calculate the price an asset would have to be for us to sell it next week, and set some orders in the present period. If the high for that period hits that level, we could simulate the trade and see how that affects our gains.

I can’t wait to model this and put it to use.

Leave a Reply

Your email address will not be published. Required fields are marked *