The Framework is what is doing the heavy lifting. It uses a Finite State Machine or FSM to implement the State Design Pattern. Don’t worry, this sounds more complicated than it is. In a nutshell, it’s a bunch of bubbles with some lines in between them. Let’s go over a simple example.
Imagine the classic EMA Crossover strategy, using the periods fast=9 and slow=20.
This is a simple example, but it showcases most of the logic happening in most strategies. And that is, go long when the EMA9 crosses up and over the EMA20, and go short when the EMA9 crosses down and below the EMA20. Obviously you can use any periods you want.
Lets see how the framework handles this logic.
The engine consists of 2 main parts, the actual Finite State Machine, and a Scanner. For now, we’ll focus on the FSM.
As you can see, there’s a timer that runs off of a Cron Job. Depending on your strategy, you’ll set this timer accordingly. In this example, we set our timer to execute 1 second past every 5 minutes. Why 5 minutes when running on the hourly? Well, not really needed, but as we’ll see in the later UI chapter, it’s nice to have data updated a bit more often than every hour.
Have a look at the strategy configuration. This is where we configure this “Tick Schedule” for the FSM.
bot: id: "phobos" fsm: isEnabled: true tradeDelay: 1000 # How big a delay between trades in milliseconds tick: schedule: "1 */5 * * * *" scanner: isEnabled: true assetDelay: 1000 interval: "1h" EMA: threshold: 30 shortlist: id: "daily-ema-crossover" dbName: "strategies_shortlist-vp" # Optional, if fetching the shortlist from a different bot tick: schedule: "15 0 * * * *" trading: liveEnabled: false
Now, at every 1 second past every 5 minutes [00:00:01, 00:05:01, 00:10:01, 17:40:01 etc…] the timer kicks in, and fetches all active trades for this strategy in the database and starts to loop through these. Every trade consists of a [symbol, interval, state, among other things]. Thus, if say BTC/USDT is in a long trade, every time the timer is triggered, the code in
State_long.js is then executed. And note the above tradeDelay. If you’re trading multiple assets in this same strategy, the FSM engine waits 1000ms before executing the next trade (or symbol). So say you’re also trading Litecoin to the Dollar, then this LTC/USDT symbol will execute at 2 seconds past every 5 minutes, thus respecting your TAAPI.IO rate-limits.
The “state code” lives in the “State Logic” box in the above diagram, and when the strategy changes state (based on your strategy logic), it will save this state in the database, and the code for this state will be run at next “tick”.
The “Bot Super Class” box, is also your implementation. It holds logic (or code) which is shared between all of your strategy states. It’s a good place to put the indicators you need if the indicators needed are the same for every state. It’s also a good place to put utility functions that are reused between states for this one strategy.
The “Framework Super Class” box, is the framework parent class that holds a lot of utility functions to help place orders, change states, fetch TA indicators etc…
The scanner part is a bit simpler. It allows you to easily scan the market for “interesting” assets. You can even (and encouraged) create shortlists so that more frequent scans can be completed faster. Imagine binance with more than 1000 symbols, it would take a while to evaluate complex TA on the hourly timeframe. But say that this “hourly logic” is only relevant for assets where the previous daily price opened below the daily EMA30, and closed above the daily EMA30, so crossed over yesterday essentially. We can then shorten this 1000+ list of symbols down to way less, and that makes an “hourly” scan much more efficient.
In this case, we’d end up with 2 scans. One to create a shortlist for all assets that crossed the EMA30, and this scan runs every day at midnight. Other scanners can then scan this shorter list, and not just one other bot, but multiple bots can share this list.
Have a look at the scanner config above that uses a shortlist from another bot that uses a different database. In a next chapter, we’ll go through making several scanners and explain how they can work together.
Live trading / simulation
In the strategy.yml configuration file, you’ll notice that live trading is disabled. In a later chapter, we’ll go through enabling live trading, along with setting order types, leverage, slippage etc…
When live trading is disabled, the system is by default in “Simulation Mode”, which simulates market orders with no leverage and 0 slippage.
Lets get started setting up our new project. We recommend setting up the project by cloning our public Github Repository, and running this with Docker. But you can also choose the “pure” NodeJS Guide.