How to Build a Trading Bot with Cloud Functions and Tradingview Webhooks

Can you outperform “buy and hold” in Ethereum?

Dmitriy
Python in Plain English

--

“Where There Are People Money May Be Made” by Adriaen van de Venne. Credit: wikiart.

Every modern human should have a bot. Better yet, a bot that makes money. Who wouldn’t want that? In this post, I’ll show you how to create a trading bot which attempts to outperform buying and holding Ethereum. We start by backtesting a few strategies and optimizing them. Then, we’ll build the logic of the bot using the Coinbase API. Finally, we’ll make the entire process automated by deploying it in the google cloud and with a little luck, we may just have a profitable bot.

“Luck plays a meaningful role in everyone’s lives.” — Jim Simons

Create the Backtest

I never believed in “if it looks too good to be true, it probably is”. So with just a few lines of code and backtesting.py, I’ve come up with some profitable-looking backtest results.

First, we install all the necessary libraries and import them.

Next, we will extend code from the quick start guide. Instead of using the Google stock to backtest, I’ve used Ethereum. I chose Ethereum because it only has 1/2 the market cap of Bitcoin but a lot more utility — the majority of the crypto market is built on it. We’ll also plug in a few different indicators from ta-lib. In addition to the simple moving average (SMA), I used an exponential moving average and a weighted moving average.

Code from one of the strategies. The rest are similar, just change the EMA part.

To make a new strategy in backtest.py, we extend the Strategy class. This essentially means we’re temporarily adding some code to their existing library. It follows the standard syntax for class creation in Python with an init(self)method to initialize the class with 2 moving averages with different lengths (n1, n2) followed by a helper function to go through the data until it finds a crossover. The standard logic in trading is to buy when a short moving average crosses above the longer one and to sell when it crosses below it.

Now we get the data.

This function takes in a pair of tradeable assets (such as ‘ETH-USD) and returns a pandas dataframe which we’ll need to pass into the backtesting engine.

To get the best strategy, we backtest and optimize each one.

This code goes through each strategy and finds the most optimal moving average parameters (n1, n2). It finds the best ones that will maximize annual returns. Notice that the prices were divided by 1000 since we only start with $100 and backtester does not support fractional trading (Coinbase does, however). I chose annual return because it’s somewhat of a more stable metric than the overall return. The backtest also returns a ton of other metrics like SQN, Calmar & Sortino rations. I’ve discarded those since this experiment is purely for massive profits. Given the wild swings in the price and lack of stop losses, the Sharpe ratio is surprisingly okay for this strategy, it’s close to 1.

Finally, we get the buy & hold % return and the best overall % return along with the strategy which produced it.

As we can see, the SMA strategy with a short-term moving average of 5 days and a long-term moving average of 15 days outperformed a buy and hold by 2.7x. Over the past 3 years, that $100 would have turned into over 5k if we used this strategy! Of course, the tragedy of backtesting is that it’s extremely difficult to tell at the time of the trade which parameters would have produced these sorts of gains. With 35 trades and a 57% win rate, that’s a little less than 1 trade per month and it’s not a bad start. Hence this is the strategy that we will wire up to trade automatically on Coinbase pro.

Create Cloud Functions

Now that we have an approximation of what a good strategy might look like, the fun part begins: deploying it. The logic is composed of a buy function and a sell function which triggers on webhooks to two Tradingview alerts.

First, we connect to the Coinbase API via CCXT.

Code 1. Uses the CCXT library to connect to the Coinbase pro API.

Now that we’ve authenticated to the Coinbase pro API, we can create the buy and sell logic.

Code 2. Buys and sells the max possible amounts via market orders.

The buy function grabs the maximum USD balance in the account and buys a specified pair with it, in our case that’s the ETH-USD pair. The sell function will get the maximum balance of ETH and sell it.

Market orders were used because Ethereum is extremely liquid and has a very tight spread, so the probability of slippage is low. Moreover, the execution time of a cloud function is limited to 30 seconds. Waiting for a limit order to execute would be better served on a server. One solution is to create other functions to periodically monitor the order queue. Just keep in mind that it’s almost always best to use limit orders in production scenarios.

The last function in the code for the cloud function will parse the incoming HTTP alert request and perform buys and sells.

Code 3. Places a buy or sell order depending on the type of Tradingview alert.

When an alert fires off from Tradingview, the “run” function is the entry point. It takes in the alert and figures out if it’s a buy or a sell. If it’s a buy and we don’t already have a position in the pair, we buy it. If it’s a sell alert and we have greater than 1 dollar’s worth to sell, we sell it.

Now we put code 1, 2, and 3 into a single file, main.py, and deploy it to Google using the gcloud command-line interface with this command:

gcloud functions deploy ethereum-strategy --entry-point=run --memory=128 --allow-unauthenticated --security-level=secure-always --timeout=30 --trigger-http --runtime=python39 --max-instances=1

This command deploys a cloud function named “ethereum-strategy” with the minimum possible hardware: 128Mb of memory and a lifetime of 30 seconds. It also sets the function named “run” as the entry point for the buy and sell logic, enables HTTPS only requests, and sets scaling to 1 so just a single function is called at a time.

A successful deployment will output the URL that’s required to fire off this function:

Create Tradingview Alerts

Now we create 2 alerts for ETHUSD. One for a buy signal when the short-term MA crosses above the long one (5 crosses above the 15) and a sell alert when it does the opposite. Alerts via webhooks are a good choice here because we aren’t doing very many orders. Strategies that require fast order execution with a lot of trades require a different setup.

All words in the message are in double-quotes.

In Tradingview, we create the simple moving average for 5 and 15 days and set the alert. Make sure to check the webhook URL option and input your URL from the previous step and create the same. Don’t forget to create the message which will be parsed by the function.

Now create another alert for a sell order when the 5 MA crosses down.

To test whether this setup works properly, we can either fire off a dummy alert from Tradingview or use a curl request to post the payload from the message of the alert from the command line.

Test the cloud function from the command line:

gcloud functions call ethereum-strategy --data '{"ticker":"ETH", "side":"sell"}'

To which you should get the following response:

result: "alert {'ticker': 'ETH', 'side': 'sell'} was received but no orders were made"

The buy functionality can be called by replacing “sell” with “buy” in the gcloud functions call command. This call will place a live trade to buy ethereum with the max possible money!

Note: there will be a few errors in the logs and this is just something to get you started on creating a trading bot so use this at your discretion.

Here are some things that could be improved:

  1. Look through the logs of the cloud function and try to fix any errors.
  2. Improve the order logic. Implement market-making orders instead of market taking. Instead of market orders, place limit orders on the bid. Give them a few seconds to fill. Make sure orders have been filled before the function execution time of 30 seconds.
  3. Find different strategies for different trading pairs.
  4. Automate the backtesting. Periodically re-run the backtest and select a new set of best parameters to maximize profit.
  5. I backtested on data from Yahoo finance, it would be better to use the data from the exchange we’re trading on.
  6. Secure the credentials with google cloud secrets and put the passphrase into the alert. Whitelist IP address from Tradingview, block requests from other ips.

Thanks for reading, stay tuned to future posts where I’ll be making improvements to this strategy and creating new ones.

Cheers and happy trading. 📈

Check out more stories from me:

--

--