The Ultimate Dollar Cost Averaging Strategy

Investing etrader Packages

Dollar cost averaging is designed to invest by reducing the risk of market timing. Use etrader and AWS to automatically invest a set amount on each trading day.

Exploring Finance https://exploringfinance.github.io/
11-21-2020

3 Key Takeaways

  1. Dollar cost averaging reduces risk associated with market timing
  2. Use etrader to make daily buys
  3. Automate the process on AWS

Dollar Cost Averaging

Dollar cost averaging (DCA) is a form of investing that attempts to reduce the risk of market timing. If someone has $10,000 to invest, they may be concerned the market is “ripe for a correction” or “may pullback over the next two years”. You always have someone predicting the next recession, including me. This can cause paralysis and prevent people from investing, keeping their positions in cash.

In my article about historical market performance, I discuss how important each year becomes over an investment timeline. Even investing on the eve of the Great Depression would have been a great investment over 30 years. That being said, it can be intimidating and nerve racking to put a large sum of money into the market at one time. Additionally, it does always feel like there is a recession coming right around the corner.

I personally fell victim to this from 2010 - 2014, which were great years to be in the market. By waiting on the sidelines, I limited my ability to capture the incredible power of compound interest. Dollar cost averaging is a great way to avoid the stress of deciding when to invest, because you invest incremental amounts over time. Over 30 years, the total impact might be relatively small, but if it prevents you from sitting on the sidelines then it’s value cannot be overstated.

Most brokerage firms offer automatic investing plans with Mutual Funds, fractional share trading is starting to grow in popularity, and robo advisors make it easy to invest when cash is deposited. All of these strategies are designed to help someone incrementally buy into the stock market. The one downside is that many of these programs have minimums that must be met, or spread out purchases by 2 or more weeks.

I personally wanted something better. Is there a way to perfect dollar cost averaging so that I could buy into the market every single day? Of course this could be done manually, but then I am left spending time everyday making decisions and entering trades. I wanted to find a way to automatically buy into the stock market every day. On down days, I am getting a deal and on up days, my previous day investment was already positive. Again, the impact over 30 years will be minimal, but the elimination of stress is priceless when leveraging a true “set it and forget it” investment strategy.

The ETRADE developer API offers a perfect solution to this problem, hence why I created the etrader package for R. While there are many trading APIs available, specifically through R (RobinHood, Alpaca, TD Ameritrade, Interactive Brokers), ETRADE offers the trifecta needed for the perfect trading API:

  1. Full service Broker Dealer that offers Retirement Accounts (missing from RobinHood and Alpaca)
  2. Commission free trading with fractional shares for DCA (missing from TD Ameritrade and Interactive Brokers)
  3. Complete automation with no manual intervention required after setup

Unfortunately, nothing is truly perfect. Fully automating a trading strategy with etrader is much more difficult than the others (see below for detailed instructions). Additionally, fractional shares only exists for Mutual Funds, but ETRADE offers a large menu of no transaction fee active and passive Mutual Funds that give more than enough options to build a comprehensive portfolio to align with your investment strategy.

Note: It is possible that after Schwab fully acquires TD Ameritrade and rolls out fractional share trading more widely, then rameritrade would be a viable option if the API is integrated. This outcome is still unknown as of 2020-11-22.

Setting up etrader

Before jumping into a fully automated trading strategy, it is important to start with the basics and get etrader up and running. In my article on trading with ramertrade, I cover the basics of the R programming language. Assuming R is installed and you have an ETRADE brokerage account, the steps below cover the process of registering for the API and logging in.

Step 1: Getting API Tokens from ETRADE

ETRADE offers excellent documentation for the API, including a Getting Started Guide. A user will need to request keys to connect to the API. It is strongly advised to use both the sandbox and production keys. There are a few steps to obtain keys as shown in the documentation and below.

API Token Request Steps

Figure 1: API Token Request Steps

You will need to complete a couple questionnaires declaring your intent. The etrader package was built for an individual user managing their own account, not a vendor, so the agreements should not prevent someone from obtaining the necessary Key and Secret tokens.

Step 2: Connecting to the ETRADE API in R

The etrader package attempts to simplify the process for logging onto ETRADE; however, the user will be required to enter their user ID and password into a web browser to complete the authentication process at least once a day.

The process below shows the log in process for a production token. See the etrader README guide for instructions using the sandbox environment.

# Install and load etrader
install.packages('etrader')
# or 
devtools::install_github("exploringfinance/etrader")
library(etrader)

# Retrieve ETRADE credentials from secure location
etkeys = readRDS('/home/rstudio/Secure/etrade_login.rds')

# Enter the Key and Secret into etrader
etrade_cred = etrd_auth_credentials(etkeys$prod_key, etkeys$prod_secret)

# Credentials are stored into R options locally on your computer, so are not required to be passed
# The next function will generate a URL for logging into ETRADE
etrd_auth_login_url()

This will automatically generate a pop up window for entering ETRADE credentials. If already logged into, ETRADE you should go straight to the screen below. Sometimes after logging in, the user is directed back to the main ETRADE site where it says “Getting Started”. If this occurs, use the link generated by etrd_auth_login_url() to continue the authentication process. The user will see a screen similar to the one below. Press ‘Accept’ to generate a verification code.

API Token Request Steps

Figure 2: API Token Request Steps

Once the verification code has been generated. Pass it into etrd_auth_access_token as shown below. This will complete the authentication process and enable the remaining etrader functions. You only have about 5 minutes to complete the entire process. It shouldn’t take more than a minute, but if it takes longer, you will need to regenerate a login URL.

access_tok = etrd_auth_access_token(verif_code = 'XX123')
# Successful authorization. etrader functions are now enabled.
# Access tokens are saved by default into options so they don't have to be passed to each function.

# Save tokens for future use if needed
# This will be important during the automation step
saveRDS(access_tok, '/home/rstudio/Secure/etrade_access.rds')

# Confirm access by checking account list
etrd_account_list()

Congratulations! You can now begin using etrader.

Create a trading script

The options here are nearly limitless. In this example, we will assume investing for a retirement account. The current annual contribution limit on IRAs is $6,000. Assuming ~250 trading days a year (52*5 - 10 holidays), that allows for $24 a day to be invested.

Below will be a full script that also uses fmpcloudr to verify the current day market hours. This script can be run directly from a CRON job assuming the ETRADE access tokens are valid for the trading day. This can be automated using RSelenium and Docker as detailed in the next section.

Note: I am using SWTSX for all investments for simplicity. I am not recommending SWTSX as an investment. Ideally the user would select 10 or more mutual funds to invest in. Some can be duplicated across multiple days if you have a position with an allocation larger than 10% or that you want spread out.

###########################
# File: etrader_example.R
# Description: Invest $24 a day into mutual funds on ETRADE
# Date: 11/21/2020
# Author: Exploring Finance
# Notes: requires access tokens to be generated with an automated script
###########################

# Load libraries
library(etrader)
library(fmpcloudr)

# Check FMP for trading hours
fmpc_set_token(readRDS('/home/rstudio/Secure/fmp.rds'))
MH = fmpc_market_hours()
trading_day = MH$marketHours$isTheStockMarketOpen

# If the market is a trading day then run script
if (trading_day) {

# Read in Access Tokens and renew them in case 2 hours have elapsed since last API call
# These tokens are created using the docker/selenium script below
access_tokens = readRDS('/home/rstudio/Secure/etrade_access.rds')

# Load ETRADE Credentials
etkeys = readRDS('/home/rstudio/Secure/etrade_login.rds')
etrade_cred = etrd_auth_credentials(etkeys$prod_key, etkeys$prod_secret)

# Activate Access Tokens in case two hours have elapsed
etrd_auth_manage_token(access_tokens = access_tokens, etrade_cred = etrade_cred)

# Create data frame of investments
# This can be as complex or robust as you desire.
# I am not recommending SWTSX as an investment
investments = data.frame(funds = rep('SWTSX',10),
                         amount = rep(12,10),
                         day = rep(1:5,2))
                         
# Read in a day counter file - this allows the app to run through each investment
# Create this using: saveRDS(1, '/home/rstudio/counter.rds')
trade_day = readRDS('/home/rstudio/counter.rds')

# Get trade details based on the trade day counter
symbols_to_buy = investments$funds[investments$day == trade_day]
amount_to_buy = investments$amount[investments$day == trade_day]

# Get account - assuming this is the desired account
actlist = etrd_account_list()
account = actlist$accountIdKey[1]

# Enter both trades for execution

# First trade
etrd_place_mf_order(account = account,
                    symbol = symbols_to_buy[1],
                    quantityType = 'DOLLAR',
                    quantity = amount_to_buy[1],
                    mfTransaction = 'buy',
                    previewOrder = 'none')

# Second Trade       
etrd_place_mf_order(account = account,
                    symbol = symbols_to_buy[2],
                    quantityType = 'DOLLAR',
                    quantity = amount_to_buy[2],
                    mfTransaction = 'buy',
                    previewOrder = 'none')
                    
# Update and save trade counter
trade_day = ifelse(trade_day == 5, 1, trade_day + 1)
saveRDS(trade_day, '/home/rstudio/counter.rds')

# Not shown here, but you can use gmailr to automate sending trade confirmations
# https://cran.r-project.org/web/packages/gmailr/gmailr.pdf

}

And that’s it! The trade script will buy $12 of two funds on each day the market is open once it has been deployed. In this article I go into detail about setting up a server and deploying a rameritrade script. The same steps can be used to deploy this script, with the one exception on generating access tokens. The next section will detail how to automate the process of generating access tokens using Docker and RSelenium.

Automate the script on AWS

As mentioned multiple times, the ETRADE API log in process requires a daily manual step of entering a username and password on the website. To fully automate the trading process on AWS, there are a handful of extra steps. This will assume an AWS server has been set up following the steps in this article.

Step 1 Setting up Docker and Selenium

To run the web-scraping script below, a Docker container needs to be set up to run selenium. First, install Docker for Linux. Docker is a very popular software that allows someone to run containers designed for specific tasks. In this example, we want to download/pull a specific docker image for running Selenium with chrome.

Step 2 Whitelisting the server

ETRADE has an additional layer of security that does not allow user login from unknown locations. To get around this, you will need to provide the IP address of your server to ETRADE so that you can complete the log in process. Whenever you start and stop the AWS server, a new IP address will be assigned. This can avoided by setting up a static IP Address on AWS.

After getting the static IP, contact ETRADE through chat support. Currently wait times are quite long unfortunately. Once connected with someone, reference ‘status code of 942’ and indicate you need to whitelist a server IP address. Provide the static IP address and wait about 10 minutes before proceeding to the next step of completing the log in process.

Update: It appears the whitelist by default only lasts for 14 days. To get around this, either request a permanent whitelist, or request a whitelist cookie and add it to the script as shown below.

Step 3 deploying a web scraping script

With the proper software installed and a whitelisted IP address. The following script can now be run to generate an access token and save them into a designated location.

# Load libraries and read in ETRADE keys
# This assumes ETRADE login details have ben saved as a list to the secure location below
library(etrader)
library(RSelenium)
etkeys = readRDS('/home/rstudio/Secure/etrade_login.rds')

# Set credentials - this is a list containing API tokens, sudo password, and ETRADE login details
etrade_cred = etrd_auth_credentials(etkeys$prod_key, etkeys$prod_secret)


# For the first execution launch a docker container using the script below
# system(paste0('echo ',etkeys$sd,' | sudo -S docker run -d -p 4444:4444 selenium/standalone-chrome:latest'))

# Once the docker container exists, start the container with the docker ID
system(paste0('echo ',etkeys$sd,' | sudo -S docker start DOCKER_ID'))
eCaps <- list(chromeOptions = list(args = c('--no-sandbox','--disable-dev-shm-usage')))
remDr <- remoteDriver(port = 4444L, browser = 'chrome',extraCapabilities = eCaps)

# Open container - force time lag to give docker time to open
Sys.sleep(5)
remDr$open()
Sys.sleep(5)


### Navigate to ETrade Login
remDr$navigate('https://us.etrade.com/e/t/user/login')
Sys.sleep(5)

# If whitelisting the server IP does not work, use the add cookie feature instead
# remDr$addCookie(name = 'SWH',
#                 value = 'OBTAIN VALUE FROM ETRADE',
#                 domain = '.etrade.com',
#                 secure = TRUE,
#                 httpOnly = TRUE)

# When testing, the code below will show the webpage
# remDr$screenshot(display = TRUE)

# Enter user credentials
remDr$findElement("xpath",'//*[@id="user_orig"]')$sendKeysToElement(list(etkeys$un))
remDr$findElement("xpath",'//*[@id="log-on-form"]/div[1]/div[2]/div/input')$sendKeysToElement(list(etkeys$pwd))
remDr$findElement("xpath",'//*[@id="logon_button"]')$clickElement()

# Go to login URL screen and accept terms
Sys.sleep(5)
loginURL = etrd_auth_login_url(etrade_cred = etrade_cred, auto_open = FALSE)
remDr$navigate(loginURL$loginURL)
Sys.sleep(5)
# Press Accept button
remDr$findElement("xpath",'/html/body/div[2]/div/div[2]/form/input[3]')$clickElement()

# Get verification code and logout
verifcode = remDr$findElement('xpath','/html/body/div[2]/div/div/input')$getElementAttribute('value')[[1]]
remDr$navigate('https://us.etrade.com/e/t/user/logout')

# Get access token and save down
access_tokens = etrd_auth_access_token(verif_code = verifcode)
saveRDS(access_tokens, paste0('/home/rstudio/Secure/etrd_acctok.rds'))


# Shut down docker container
system(paste0('echo ',etkeys$sd,' | sudo -S docker stop DOCKER_ID'))

Once this script is written, it can then be scheduled to run everyday at 9 am Eastern to generate tokens on a daily basis going forward.

Wrapping up

In this article, we covered the benefits of dollar cost averaging, the different trade APIs available, and an example of automating investment using etrader. The automated log in process for etrader is more labor intensive to set up than the other trade APIs, but once the process is complete, a fully automated dollar cost averaging strategy can be implemented.

Disclosure: This article is not intended to be financial advice. Anyone using the etrader package does so at their own risk and should understand the trades they are making. It is strongly recommended to use the sandbox environment or make trends in off market hours first to ensure the order entry is correct.