A Farewell to Swell: DIY Socially Responsible Investing through Alpaca

A Farewell to Swell: DIY Socially Responsible Investing through Alpaca


Photo by Gustavo Quepón on Unsplash

I was saddened to learn that on July 24th, 2019 Swell Investing stopped accepting new customers and would be shutting down operations by the end of August. Founded in 2017, Swell was an investment advisor and platform that focused exclusively on impact investing.

What is impact investing?

Impact, or socially responsible investing (SRI), includes and is also called, among others:

  • community investing
  • ethical investing
  • green investing
  • mission-related investing
  • responsible investing
  • sustainable investing
  • values-based investing

As described by the U.S. SIF Foundation, “SRI is an investment discipline that considers environmental, social and corporate governance (ESG) criteria to generate long-term competitive financial returns and positive societal impact.”

Interest in SRI has grown significantly in recent years, as depicted in the chart below. The U.S. SIF Foundation’s Report on US Sustainable, Responsible and Impact Investing Trends identified $12.0 trillion in total assets under management at the end of 2017 using one or more SRI strategies.

Farewell Swell, You Will Be Missed

Although I wouldn’t call Swell a competitor, as an employee of fintech company Alpaca, which provides a developer-friendly commission-free brokerage (no, we’re not Robinhood), I understand how challenging it is to help build an innovative investing and trading service from the ground up, and I admired Swell’s commitment to socially responsible investing.

As a tribute to Swell, I decided to write a simple but powerful python script as an example of how Alpaca users can passively invest in socially responsible companies using representative ETFs. Admittedly, this is a do-it-yourself implementation that doesn’t have any of the bells and whistles that Swell offered. No visuals, no slick mobile app, no automated rebalancing, and no set and forget allocation tools. On the other hand, there are no investment advisor fees or trading commissions. Critically though, it requires a bit of coding knowledge. You’ll need to have Python 3.5+ and the Alpaca Trade API installed to run this script. If you like the concept of this algo but don’t know how to code, leave a comment or get in touch and we’ll work on creating a Google sheets or Colab version.

Keep in mind that this is only an example to get you started. If you decide that you want to commit your own money to an automated strategy, you should first test the performance of the principles yourself. Fortunately, Alpaca provides a “paper trading” platform, so you can see this script work without having to put your real account balance on the line.

How the Algo Works

  1. Does it invest in stocks, ETFs, or mutual funds?

In this example, I’ve used one ETF for each of these various SRI themes:

The above table is for illustrative purposes only. This is not an offer, solicitation of an offer, or advice to buy or sell securities, or open a brokerage account.

  1. Does the algo invest all or only a portion of your money?

It’s up to you. You’ll need to enter the percentage of your account equity you want to allocate to each SRI theme as a script argument. The algo will try to match your desired allocation, taking into consideration the money to allocate (if your account and target allocation are too small, you might unintentionally end up with a 0% allocation for some themes!). Any unallocated portion will remain in cash. For example, and for illustrative purposes only, here’s how we would allocate 90% of our funds across 6 themes with varying percentages (with the remaining 10% left in cash):

python3 sri.py --diversified=20 --water=20 --energy=20 --health=10 --disease=10 --gender=10

  1. How frequently does the algo rebalance? Daily, weekly, monthly?

The algo I’ve created doesn’t have a defined rebalancing schedule. Any time you want to rebalance, you simply run the script and enter your desired portfolio allocations.

  1. What’s the minimum account balance I need to use the SRI algo?

Since Alpaca does not currently support fractional shares (though we are working on adding this feature!), the minimum account balance you’ll need to use this algo is enough to buy at least 1 share of each of your desired thematic exposures. But generally speaking, the algo’s allocation model works better with at least $1,000 and can improve as even larger amounts are invested.

The Code

Without further ado, here’s the code in its entirety (and feel free to build upon this):

"""
Do-it-yourself passive socially responsible investing example algo
Author: evan@alpaca.markets
Notes:
*New SRI portfolio only accurate when run during regular trading hours
*All orders submitted are MARKET DAY orders
*Tries to obtain thematic allocations as close as possible to desired
*Minimum account balance you'll need to use this algo is enough to buy at least 1 share of each of your desired thematic exposures
*Generally speaking, the allocation model works better with at least $1,000 and improves as even larger amounts are invested
*Liquidating orders in non-thematic stocks to free up capital when necessary to fulfill the desired allocation
are in no particular order and will liquidate the entire position before evaluating whether or not to liquidate another.
*Algo is for illustrative purposes only and is not a recommendation to buy or sell a security.
"""

import argparse
import math
import alpaca_trade_api as ata

SYMBOL_MAP = {'diversified':["Diversified SRI","USSG"],
              'water':["Clean Water","PHO"],
              'energy':["Renewable Energy","ICLN"],
              'health':["Healthy Living","BFIT"],
              'disease':["Disease Eradication","XBI"],
              'gender':["Gender Diversity","SHE"]}

def print_acct(positions,equity,themes):
    print("Theme                | Symbol | Qty    | Market Value | % of Portfolio ")
    print("-----------------------------------------------------------------------")
    for t in themes:
        if t.target==0:
            print("%-20s | %-6s | %-6s | %-12s | %-14s" % (t.name, "0", "0", "0", "0"))
        else:
            for p in positions:
                if t.symbol == p.symbol:
                    print("%-20s | %-6s | %-6s | %-12s | %-14s" % (t.name,p.symbol,p.qty, p.market_value, round(float(p.market_value)/float(equity)*100,2)))
                    break

class Theme():
    def __init__(self,name,alloc,symbol,price,amount):
        self.name = name
        self.symbol = symbol
        self.ref_price = price
        self.target = alloc/100.0
        self.shares = math.floor((amount*self.target)/self.ref_price)
        self.value = self.shares*self.ref_price
        self.actual = round(self.value/amount,4)
        self.order = []


def main(args):
    #initialize
    api = ata.REST(key_id='<your key id>', secret_key='<your secret key>',base_url='https://api.alpaca.markets', api_version='v2')
    acct = api.get_account()
    equity = float(acct.equity)
    positions = api.list_positions()
    if args.amount:
        amount = int(args.amount)
    else:
        amount = float(equity)

    print("\nAmount to allocate/rebalance:", amount)
    print("Account equity:", equity)

    a_sum = 0
    orders = []
    themes = []
    symbols = []

    #build each theme and order
    for arg in vars(args):
        if arg in SYMBOL_MAP:
            symbol = SYMBOL_MAP[arg][1]
            symbols += [symbol]
            name = SYMBOL_MAP[arg][0]
            alloc = vars(args)[arg]
            a_sum += alloc
            bars = api.get_barset(symbol,'minute',limit=10)
            price = bars[symbol][-1].c * 1.04
            theme = Theme(name, alloc, symbol, price, amount)
            #initialize order assuming no existing position
            theme.order = ["buy", theme.shares, theme.symbol, theme.value]
            themes += [theme]
            # check existing positions to determine qty to buy/sell for rebalance
            for p in positions:
                if symbol == p.symbol:
                    qty = theme.shares - int(p.qty)
                    if qty < 0:
                        theme.order = ["sell", abs(qty), theme.symbol, qty*theme.ref_price]
                    else:
                        theme.order = ["buy", qty, theme.symbol, qty*theme.ref_price]
                    break
            if theme.order[1]!=0:
                orders += [theme.order]
    assert a_sum <= 100, "Sum of allocations exceeds 100%"

    #output current SRI state
    print("\nCurrent SRI Portfolio")
    print_acct(positions,equity,themes)

    #generate liquidating orders in other holdings if necessary to free up cash
    approx_value_to_buy = sum(o[3] for o in orders)
    portfolio_value = float(acct.long_market_value) + abs(float(acct.short_market_value))
    portfolio_avail = equity - portfolio_value
    print("\nValue of all holdings:",portfolio_value)
    if portfolio_avail < approx_value_to_buy:
        deficit = round(approx_value_to_buy - portfolio_avail,2)
        print("Need to free up %s to rebalance." %deficit)
        for p in positions:
            if p.symbol not in symbols:
                print("\nSubmitting liquidating orders...")
                if deficit>0:
                    q = int(p.qty)
                    if q<0:
                        print('%s %s %s' % ("buy", abs(q), p.symbol))
                        api.submit_order(symbol=p.symbol, qty=abs(q), side="buy", type='market', time_in_force='day')
                    if q>0:
                        print('%s %s %s' % ("sell", q, p.symbol))
                        api.submit_order(symbol=p.symbol, qty=q, side="sell", type='market', time_in_force='day')
                    b = api.get_barset(p.symbol, 'minute', limit=10)
                    p = b[p.symbol][-1].c * 1.04
                    mv = round(abs(p*q),2)
                    deficit -= mv
                    if deficit>0:
                        print("Still need to free up %s to rebalance." %deficit)
                    else:
                        print("Done freeing up funds to invest.")

    #output thematic rebalance orders and final account state
    print("\nSubmitting orders...")
    for o in orders:
        print('%s %s %s' %(o[0],o[1],o[2]))
        api.submit_order(symbol=o[2], qty=o[1], side=o[0], type='market', time_in_force='day')
    print("\nNew SRI Portfolio")
    equity = api.get_account().equity
    print_acct(api.list_positions(),equity,themes)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--amount', help='$ amount to allocate, if no value specified then uses current account equity')
    parser.add_argument('--diversified', type=int, help='% alloc to Diversified SRI(high ESG performance)', required=True)
    parser.add_argument('--water', type=int, help='% alloc to Clean Water', required=True)
    parser.add_argument('--energy', type=int, help='% alloc to Renewable Energy', required=True)
    parser.add_argument('--health', type=int, help='% alloc to Healthy Living', required=True)
    parser.add_argument('--disease', type=int, help='% alloc to Disease Eradication', required=True)
    parser.add_argument('--gender', type=int, help='% alloc to Gender Diversity', required=True)
    args = parser.parse_args()
    main(args)

Technology and services are offered by AlpacaDB, Inc. Brokerage services are provided by Alpaca Securities LLC, member FINRA/SIPC. Alpaca Securities LLC is a wholly-owned subsidiary of AlpacaDB, Inc.

This is not an offer, solicitation of an offer, or advice to buy or sell securities, or open a brokerage account in any jurisdiction where Alpaca is not registered (Alpaca is registered only in the United States).

All investments involve risk and the past performance of a security, or financial product does not guarantee future results or returns. Keep in mind that while diversification may help spread risk it does not assure a profit, or protect against loss, in a down market. There is always the potential of losing money when you invest in securities, or other financial products. Investors should consider their investment objectives and risks carefully before investing.

There are risks unique to automated trading algorithms that you should know about and plan for. You should setup a method or system of continuous monitoring or alerting to let you know if there is a mechanical failure, such as connectivity issues, power loss, a computer crash, or system quirk. You should also monitor for instances where your automated trading system experiences anomalies that could result in errant, missing, or duplicated orders. A more complete description of these and other risks can be found in our FAQ section.

ETFs can entail risks similar to direct stock ownership, including market, sector, or industry risks. Some ETFs may involve international risk, currency risk, commodity risk, and interest rate risk. Trading prices may not reflect the net asset value of the underlying securities.

Commission-Free trading means that there are no commission charges for Alpaca brokerage accounts that trade U.S. listed securities through an API. Relevant SEC and FINRA fees may apply.

© 2019 Alpaca Securities LLC. All rights reserved.

© 2019 AlpacaDB. All rights reserved.


2 Likes