Algorithmic Trading with Scala and Akka — How to Start

Jan Rock
13 min readJul 23, 2019

--

1. Introduction
There is a new trend for traders to develop the coding skillset for themselves and become algorithmic traders. Most of the tools and brokers offer well-documented APIs with UIs to simplify the access. It is an excellent approach to learn how to code trading applications. There are many free API providers with demo accounts topped up with virtual money to evaluate the strategy without any risk. There are some positive and negative aspects associated with the demo accounts, because the difference between the real market, fees, spread and sometimes manipulated prices to convince potential trader to subscribe to a real account.

There are many great courses for Python or R, the most popular programming languages in the trading arena. Scala programming language with Akka Actors framework mentioned in the article is also very popular; however, it requires far more coding background. Online trading providers have also offered courses related to algorithmic trading, unfortunately mostly focused on particular tool or broker with “blackbox” capabilities doing something without transparency of the actions inside.

What is Algorithmic Trading?
Algorithmic trading relies on computer programs that execute algorithms to automate some, or all, elements of a trading strategy. Algorithms are a sequence of steps or rules to achieve a goal and can take many forms. In the case of machine learning (ML), algorithms pursue the objective of learning other algorithms, namely rules, to achieve a target based on data, such as minimising a prediction error.[1]

At the most basic level, the algorithm can be a set of conditions periodically checked and with another set of actions (open or closed position) when a state is valid. The algorithm needs two inputs. In the case of Foreign Exchange (FX) trading, prices and signals data streams. The signal can be received from external paid API and generated by algorithm from ingested stream data not always just prices.

The Main Algorithmic Trading Tools
The title of the document is “… trading with Akka/Scala”, therefore the focus here is on programming tools, market, trading and visualisation tools.

JetBrains IntelliJ IDE or “old and good” Eclipse are the two top tools. Together with JDK, Apache Spark and SBT and Scala plugins compose ideal toolset for development Scala-based apps. Linux or macOS is more development-friendly environments.
(Author’s note: I have been surprised by Apache Spark performance on Windows, but it wasn’t easy to configure and tune up all of the pieces)

Lightbend Akka is a framework using the Actor model described first by Carl Hewitt, Peter Bishop and Richard Steiger in the A universal modular ACTOR formalism for artificial intelligence paper from 1973. [2]
Akka is a combination of Actors which provide simple and high-level abstractions for distribution, concurrency and parallelism. Asynchronous, non-blocking and highly performant message-driven programming model is an absolute must for trading applications.
There can be very lightweight event-driven processes (millions of actors per GB of heap memory) make the application suitable to run in containers.
Fault Tolerance “let-it-crash” semantics makes the code highly fault-tolerant systems that self-heal and never stop. Akka framework is designed to work in a distributed environment. All interactions of actors use simple message passing in asynchronous mode.
Last advantage to mention, state changes experienced by an actor can optionally be persisted and replayed when the actor is started or restarted. This ability allows actors to recover their state, even after JVM crashes or when being migrated to another node. Akka is an option to have a framework performing and behaving very carefully to the low latency C++ trading applications.

Kubernetes (used as the environment for deployment of the demo trading application) is a portable, extensible, open-source platform for managing containerised workloads and services, that facilitates both declarative configuration and automation. It has a vast, rapidly growing ecosystem and list of contributors. Kubernetes ecosystem, services, tools and technology partners are widely available.
In general, the containers are very similar to virtual machines. The container is far more flexible to utilise HW. It has its CPU, operating memory, temporary or persistent storage, networking layer and operating system. Containers flexibility means to be decoupled from the underlying infrastructure, stay portable across clouds and OS distributions. Containers mean for developers more flexibility and simplicity to deploy, run and test code. Capabilities like service discovery and load balancing, storage orchestration (automount, scale, etc.), automated rollouts and rollbacks, automatic bin packing (computation resource management), self-healing (restarts, replacement, etc.) secret and configuration management (complex security to manage sensitive information) are in place in default.
Deployment on Google Cloud Platform using Google Kubernetes Engine with Container Registry is an ideal solution for the final algorithm.

VisualVM is a simple and great tool to analyse performance, memory and thread management related to the trading app.

The next part has to be a real-time API to get the price data and execute trades. Oanda is a global leader in online multi-asset trading services, and currency data and analytics with free of charge demo account topped up with GBP 100.000 and not too different behaviour from the real market data. There is an option to use their API with provided packages or libraries. Another alternative uses direct HTTP/S calls which offer better control of exchanged data. There is another benefit such as UI with graphical interpretation of price data, trading information, trades, positions, orders, account status, and so on. https://dl.acm.org/citation.cfm?id=1624804

Algorithmic Trading Strategies
There are many books about trading strategies, but for absolute beginners, Forex for Beginners by Anna Coulling gives a great intro. The code in section 2 follows the recommendation on the main cross-currency pairs[3], which are frequently traded and Gold in pair with USD (XAU_USD) is ideal to start. XAU_USD is traded 24/7, and the main peak between 7 am. and 7 pm. BST when London and New York are open.

Sydney and Tokyo do not have a too significant impact on this “combo”. XAU_USD is also pair with well-known patterns, e.g. Similarly, if a candle closes above resistance on the Dollar Index chart, a short trade is triggered on the XAU/USD the following day.[4] (picture)

The moving average (MA) is a simple technical analysis tool that smooths out price data by creating a continually updated average price. MA is always part of the complex algorithms to define safe zones to trigger action. The average is taken over a specific flowing time window (minutes, hours, days etc.)

Demo algorithm uses multiple windows to determine the trend and execute trades in the right moment to maximise profit and minimise the risk. In the real-world example, there will be hundreds of different methods processed in parallel as fast as possible to trigger actions. The methods are based on statistics and in the same following external factors and powers (macroeconomics, politics, social networks etc.) Build a balanced strategy with the right weight to signals produced by the algorithm is equal to future success.

There are several strategy types to inform the design of your algorithmic trading application.
• Macro-economic news and events (e.g. changes in interest rate)
• Fundamental analysis (e.g. revenue data, earnings)
• Statistical analysis (e.g. correlation)
• Technical analysis (e.g. numerical analysis, moving averages)
• The market microstructure (e.g. arbitrage or trade infrastructure)
• Composing for preliminary research

Nowadays, machine learning and deep learning are heavily utilised to find the right balance and determine common and mainly hidden patterns between signals. Jannes Klaas, in his book Machine Learning for Finance[5], describes LSTM (Long Short-Term Memory) type of neural network as the best for time series trading data. A more detailed exploration can be read in the 1994 paper, learning long-term dependencies with gradient descent is difficult, available at https://ieeexplore.ieee.org/document/279181 by Yoshua Bengio, Patrice Simard, and Paolo Frasconi.

Recurrent neural networks can be used to map input sequences to output sequences, such as for recognition, production or prediction problems. However, practical difficulties have been reported in training recurrent neural networks to perform tasks in which the temporal contingencies present in the input/output sequences span long intervals. We show why gradient-based learning algorithms face an increasingly difficult problem as the duration of the dependencies to be captured increases. These results expose a trade-off between efficient learning by gradient descent and latching on information for long periods. Based on an understanding of this problem, alternatives to standard gradient descent are considered.[6]

Backtesting and Time Machine
Backtesting is a process, and environment builds to validate trading strategy and algorithm. The point of backtesting is to spot the moments when the expectation does not meet the action. This method helps to discover a new pattern which is not covered and could cause potential money loss.
Another type of testing is “Time Machine”. Nowadays, companies focus their interest from backtesting to forward testing. Machine learning allowed to build a model on time series data to simulate behaviour adjusted by seasonal and other events to create a future market environment. Thanks to the option to “travel in time”, the strategy can be evaluated in different market conditions, filtering or acting on black swan type events, social media comments, and so on.

Algorithmic Trading Design Optimization
When the application is coded and working, the next stage is to maximise its performance while minimising the overfitting bias. It is crucial and from the beginning to pick the right performance measures to analyse collected risk and reward data, as well as consistency (e.g. Sharpe ratio), is the key to optimisation. Example of an overfitting bias occurs when an algorithm is strictly based on past data; it gives off the illusion of high performance, but since the future never completely resembles the past, it may fail.

Live Execution
There are several ways to start trading. PC or laptop to running the code is ideal for full control and monitoring. UI offered by Oanda can be used together with Tradingview.com to get a set of free of charge trading analysis tools. Usually, the first attempts fail because the set of rules does not cover all possible scenarios. A developer has to be prepared for the emotional ups and downs. The next stage is usually a cloud deployment to let the algorithm trades 24/7. The caveat is related to simple algorithms which need manual interventions all time to not lose a lot of money because of unexpected market events. On the other hand, the application will run on reliable hardware and in an environment with guaranteed Internet connectivity.

The Bottom Line
The term comes from the bottom position on net income in the company earnings report. It means an important number combining results of total profit and all of the losses with, of course, all the costs. Bottom Line has to monitor and continually discussed with the team to make sure the risk is on the right level. Algorithmic trading should create the base, low risk, lower profit, but significant volume. Models should be adjustable to follow the overall company strategy and the actual situation.

2. Code
Postgres database running on Kubernetes cluster in multimode deployment as the price data storage is probably the most basic component of the stack. Two tables hold the price and statistical data.

create table if not exists akkapit.price
(
id serial not null
constraint price_pk
primary key,
ts timestamp not null,
instrument varchar(10) not null,
o_price double precision,
h_price double precision,
l_price double precision,
c_price double precision
); create table if not exists akkapit.stats
(
id serial not null
constraint stats_pk
primary key,
ts timestamp not null,
instrument varchar(20) not null,
stats_id varchar(20),
stats_val double precision,
stats_desc varchar(50)
);

Main function triggers every 5 seconds two actions using Akka Actor System to get the prices and trade status with the moving averages strategy.

// Build ActorSystem (2 actors)
val system = ActorSystem(“System”)
val ApiActorStatus: ActorRef = system.actorOf(Props[ApiActorStatus], name = “ApiActorStatus”)
val ApiActorPrice: ActorRef = system.actorOf(Props[ApiActorPrice], name = “ApiActorPrice”)

def main(args: Array[String]): Unit = {
if (tradingHours) {
system.scheduler.schedule(0 seconds, 5 seconds)(Price())
system.scheduler.schedule(0 seconds, 5 seconds)(Status())}}

To manage the Postgres database from the application — an example of price data inserts and read.

def dbins(instrument: String, o_price: Double, h_price: Double, l_price: Double, c_price: Double): Unit = {
try {
val prep = conn.prepareStatement(“INSERT INTO akkapit.price” +
“ (ts, instrument, o_price, h_price, l_price, c_price)” +
“ VALUES (?, ?, ?, ?, ?, ?) “)
prep.setTimestamp(1, from(Instant.now()))
prep.setString(2, instrument)
prep.setDouble(3, o_price)
prep.setDouble(4, h_price)
prep.setDouble(5, l_price)
prep.setDouble(6, c_price)
prep.executeUpdate
}
}

def dbget(limit: Int):Double = {
try {
val prep = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)
val rs = prep.executeQuery(“SELECT AVG(t.c_price) AS avg_c FROM(“ +
“SELECT c_price FROM akkapit.price AS p ORDER BY p.ts DESC LIMIT “+ limit +”) t;”)
while (rs.next) {
res = rs.getString(“avg_c”).toDouble
}
}
res
}

Example of statistical value based on the constantly updated dataset.

def dbgetmax():Double = {
try {
val prep = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)
val rs = prep.executeQuery(“SELECT Date(t.ts), t.c_price FROM akkapit.akkapit.price t INNER JOIN (SELECT MAX(c_price) AS MaxC FROM akkapit.akkapit.price GROUP BY Date(ts)) q ON t.c_price = q.MaxC ORDER BY Date(ts) DESC LIMIT 1;”)
while (rs.next) {
res = rs.getString(“c_price”).toDouble
}}res}

Buy decision with Moving averages.

if (jAccountTradeCount.toInt < 50) {
if (!buy_lock &&
last_5 && // last 5 price(close) increasing
dbget(12) < last && // 1min MA
dbget(120) < last && // 10min MA
dbget(720) < last && // 60min MA
mid_lvt < last // above daily AVG
) {
buy(-1) // execute SELL order
}
}

Sell decision with defined coefficient of profit.

for (i <- 0 to tradeCount) {
totalPnL += jTradeUnrealizedPL(i).toDouble // trade P/L

// 1410 * 0.995 =~ 1402 > current_price
if (!sell_lock) {
if ((jTradePrice(i).toDouble * coef) > dbgetlast()) {
sell(jTradeId(i).toInt)
}
}

tradeCount — 1
}

Several hundred lines of code cover the whole concept of algorithmic trading. The complexity can be added to the buy/sell module. Machine learning (LSTM), signals from external API can be easily implemented and improve the overall performance.

3. Results
Trading algorithm with simple MA strategy is a very safe way to trade. Oanda UI shows an example when are the trades executed and using just a common sense that is probably the best moment to “sell”.

30 minutes later:

Day #1 trading closed with GBP 311.82 realised P/L. (the profit is automatically converted from USD to GBP as the default currency of the account.

The following daily increment is very similar to ~£300–400.

4. Recommendations

Model adjustment
In general, model tuning can be a very complex exercise that involves people, compute resources and time. Models based on a set of proven rules without any machine learning have a more straightforward process around tuning. These models can be easily back-tested on historical data to check their worth before diving with real money. Import is to understand the reasons what the model did and what triggered the action. The complexity of the ML and AI models sometimes completely hide the impulse to the long or short action.
The recommendation can be related to adding long-term moving averages, e.g. 50-day and 15-day with appropriate logic. Models application wrappers can be extended to alerts, pop-up messages, or updating dashboards. This capability can eliminate the need for manual monitoring and action. Other improvements are more related to risk management and safeties around trading.

Risk management
Trading single currency-commodity pair will always bring a risk. To balance the potential caveat can add cross pair such as USD_GBP to secure unexpected events with betting against or on USD. Trading profit target around 5 to 10 per cent over an extensive period is an excellent result for the initial strategy. Good practice and basic rule are to keep half of the profit on a side and continue trading just with the second half. Davis Edwards’ book Risk management in trading: techniques to drive the profitability of hedge funds and trading desks[7] is ideal for an introduction to Risk Management and all best practices.[8]

Risk reduction strategy
Another option for risk reduction is to add the Forex Economic calendar and not trade these critical days until the complexity of the algorithm will be ready for that.
The algorithm should also contain automated shutdown procedures in case of fast changes on the market, reaching certain thresholds, e.g. a specific number of open trades, used margin, traded volume, etc.

Parameter management
Most of the MA parameters and continuously updated and stored for the algorithm into the database. The code should have a control mechanism with a set of action in case of the database fail. Missing parameters and algorithm using default values can cause massive money lost. Database cluster running as several instances with the load balancer on Kubernetes can be the solution to minimise the risk.

Conclusion
No algorithm or trader is right every time, but both should make money more often than lose money and profitable algorithms or trades should make more than the losing ones. The easiest way to do all these things is to use brain, discipline, stay modest and do not expect amazing results from the beginning. Algorithmic trading is not just a financial discipline, but also an excellent opportunity to master programming skill within a real-time environment, combining technology, business and economics knowledge. Good luck!

5. Bibliography and Web Sources

[1] JENSEN, Stefan. Hands-On Machine Learning for Algorithmic Trading. 2018. United Kingdom: Published by Packt Publishing, 2018. ISBN 9781789346411.

[2] Carl Hewitt, Peter Bishop, Richard Steiger. 1973. A universal modular ACTOR formalism for artificial intelligence. https://dl.acm.org/citation.cfm?id=1624804

[3] COULLING, Anna. Forex for Beginners: What you need to know to get started. 2013. United Kingdom: CreateSpace Independent Publishing Platform, 2013. ISBN 9781494753757.

[4] SINGH, Mario. 17 Proven Currency Trading Strategies: How to Profit in the Forex Market. Hoboken, NJ: Wiley, [2013]. ISBN 9781118385517.

[5] KLAAS, Jannes. Machine Learning for Finance. 2019. United Kingdom: Packt Publishing, 2019. ISBN 9781789136364.

[6] BENGIO Yoshua, SIMARD Patrice, FRASCONI Paolo. 1994. Learning long-term dependencies with gradient descent is difficult.
https://ieeexplore.ieee.org/document/279181

[7] EDWARDS, Davis W. Risk management in trading: techniques to drive profitability of hedge funds and trading desks. Hoboken: Wiley, 2014. ISBN 978–1–118–76858–7.

[8] NATIONS, Scott. The complete book of option spreads and combinations: strategies for income generation, directional moves, and risk reduction. Hoboken, New Jersey: John Wiley & Sons, [2014]. ISBN 9781118805459.

--

--

Jan Rock
Jan Rock

No responses yet