Introduction
This tutorial builds on from what we’ve done in previous sessions to build a small demo app that watches exchange book prices and then executes a trade if the threshold is reached.
For added winning, we’ll send a push notification to your phone when this happens.
Triggers
Triggers are little more than semantic sugar that abstract out event listeners and replaces them with functions that make it much clearer what the intent of a specific event listener is.
So instead of
feed.on('data', msg => {
if (msg.type !== 'ticker' || msg.productId !== 'BTC-EUR') {
return;
}
if (msg.productId == 'BTC-EUR' && msg.price && msg.price > 1000) {
doSomething(msg as TickerMessage);
}
});
we have
CBPTT.Core.createPriceTrigger(feed, 'BTC-EUR', 1000)
.setAction((event: TickerMessage) => {
doSomething(event);
});
The second snippet makes it explicit that we’re executing doSomething
based on a price threshold trigger. The Price trigger implementation also has a few extra nuances: It handles price changes across the threshold whether the price is rising or falling; and the trigger clears after the first
time it has activated, so you won’t be spammed with events.
Push notifications
We’ll be using PushBullet to handle push notifications to our phone for this tutorial.
You’ll need a (free) account on the PushBullet website. You can use a gmail address to sign up. You also need to install the PushBullet app onto your phone (there are Android and iOS versions).
Then you need to grab the following information:
- Your API key - Go to the settings page and click “Create an access token”. Save this string to the
PUSHBULLET_KEY
environment variable in your OS. - Your device ID - First add your device to your account using the mobile app. Then, on your computer, run
curl --header "Access-Token: $PUSHBULLET_KEY" https://api.pushbullet.com/v2/devices
in a console and copy theiden
string associated with your device. Store this in thePUSHBULLET_DEVICE_ID
envar.
The demo
tutorials/t005_alertTrader.ts
.
The basic strategy of our bot is this:
- After configuring and connecting to the message feed,
- Get the next ticker price
- Set two triggers, once above and one below the price with a given spread between the two
- If an event triggers,
- push a notification to my phone
- and place a small trade, buying at the lower price and selling at the higher price
Note: You need the following environment variables to be set correctly for this to work:
- PUSHBULLET_KEY
- PUSHBULLET_DEVICE_ID
- COINBASE_PRO_PASSPHRASE
- COINBASE_PRO_KEY
- COINBASE_PRO_SECRET
If you don’t have one, you can create a Coinbase Pro API key on the website. Make sure to enable the view
and trading
permissions.
Now that all the admin is out of the way, let’s get coding!
Usually we use FeedFactory
to grab a feed, but since we’re only interested in ticker messages, let’s save some bandwidth and only subscribe to that channel:
const options: CoinbaseProFeedConfig = {
logger: logger,
auth: { key: null, secret: null, passphrase: null}, // use public feed
channels: ['ticker'],
wsUrl: COINBASE_PRO_WS_FEED,
apiUrl: COINBASE_PRO_API_URL
};
CBPTT.Factories.CoinbasePro.getSubscribedFeeds(options, [product]).then((feed: CoinbaseProFeed) => {
...
});
Pretty painless. Note that we nulled out the auth
object to force the feed to use unauthenticated messages. You can set auth: null
to just use the defaults, which since you have your Coinbase Pro API keys set in the environment, will automatically use those and receive authenticated messages (nice if you want to confim when your trades are filled).
Now we can make use of a TickerTrigger to get the next ticker from the websocket feed. We extract the current price, and use that as the basis to create two price triggers, one above, and one below the current price:
CBPTT.Core.createTickerTrigger(feed, product).setAction((ticker: TickerMessage) => {
const currentPrice = ticker.price;
CBPTT.Core.createPriceTrigger(feed, product, currentPrice.minus(spread)).setAction((event: TickerMessage) => {
pushMessage('Price Trigger', `${base} price has fallen and is now ${event.price} ${quote} on ${product} on Coinbase Pro`);
submitTrade('buy', '0.01');
});
CBPTT.Core.createPriceTrigger(feed, product, currentPrice.plus(spread)).setAction((event: TickerMessage) => {
pushMessage('Price Trigger', `${base} price has risen and is now ${event.price} ${quote} on ${product} on Coinbase Pro`);
submitTrade('buy', '0.01');
});
});
The pushMessage
function just uses the PushBullet
A{I to direct the information to your phone:
const pusher = new CBPTT.utils.PushBullet(process.env.PUSHBULLET_KEY);
function pushMessage(title: string, msg: string): void {
pusher.note(deviceID, title, msg, (err: Error, res: any) => {
if (err) {
logger.log('error', 'Push message failed', err);
return;
}
logger.log('info', 'Push message result', res);
});
}
and submitTrade
uses the REST API to place a trade for you:
const coinbaseProAPI = CBPTT.Factories.CoinbasePro.DefaultAPI(logger);
function submitTrade(side: string, amount: string) {
const order: PlaceOrderMessage = {
type: 'order',
time: null,
productId: product,
orderType: 'market',
side: side,
size: amount
};
coinbaseProAPI.placeOrder(order).then((result: LiveOrder) => {
pushMessage('Order executed', `Order to sell 0.1 ${base} placed. Result: ${result.status}`);
});
}
Next steps
This is just a little proof-of-concept app. But it can be used as a template to do some real bot-making.
Here’s are some suggestions to play around with this code some more:
- Use
commander
to specify products, price targets and trade orders from the command line. - Add a
LiveOrderbook
and add some of your secret trading logic to estimate the upper and lower price ranges automatically, rather than specifying them manually.- Once you have a LiveOrderbook, you might consider using a
Trader
class to place your trades rather than using the REST API directly.Trader
will be the focus of another tutorial.
- Once you have a LiveOrderbook, you might consider using a
- Write a new Trigger that responds to
tradeFinalized
messages so that you can be notified when you order is filled. - Use the API to fetch your balances and trade based on how much you have available.
- Add some feedback from the push notification to reset targets (e.g. “Drop targets by $20”)