I'm a system trader with over 20 years of software development experience. For more than 10 years I participated in projects to build custom, integrated systems for enterprise customers.

When I started to build our first trading system in AFL the indicator part was easy and fun. AFL is cool. I don’t care for any scripting language but I really like the idea of array processing. I really like thinking in sets and vectors. Efficient and elegant. And AFL scripts have the advantage of quick fixing. Edit, save, rerun. That's fine. As I advanced in our trading system development I started to realize a few problems as well.

Trading system development is a special kind of software development. Its full lifecycle process is more complicated, but there are a lot of common things. So why not use the tools of software development as well? The very first thing I started to use was a source control tool to keep track of different versions of files of our trading systems. Later I started to use Visual Studio.Net to write AFLs after searching for a missing bracket in an include file for almost a day. As the code grew and there were many include files and plug-ins I had to manage their deployment, so I used custom Visual Studio projects to edit, build and deploy the script and plug-in projects together.

During this long journey (~3 years) I found three development areas where I just could get a really good solution:

AFL Plug-in development

Real time trading logic in AFL

Debugging and testing complex AFL logic

Win 32 plug-ins are fine for the hard core C developers. But it just takes too much time and effort to write and test them. A trading system using slower than a minute timeframe does not have to be coded in assembly or C. On the other hand markets continuously change. So does the trading logic. Why not use a language that is much easier to use and maintain? Why should I bother about pointers!? Why can't I use the AFL array operators in plug-ins? I want to code trading logic, not the C glue code to call a simple built-in function. If my trading system needs to communicate with an external system (trading logic, email, etc) why should I write C code or write COM objects?

Real time trading logic is a different problem. I know different execution environments (SQL , web apps, Windows client and server applications, Windows services, COM components, etc.). For me AFL scripts and the real time trading logic managing order states just do not fit. It is like matching water and fire. AmiBroker is a stateless execution environment using AFL scripts. I know there are static variables. I know it is doable. Our current live system still uses AFL and IBController to manage trading. But the whole idea behind AmiBroker and AFL script is a stateless design that processes time series data. AmiBroker and AFL scripts forget everything in between two executions. Just like a decent web application execution environment. At each HTTP request (in our case execution cycle) the whole state has to be recovered from some storage (in our case static variables). As long as we develop indicators and trade signals to backtest and optimize them this stateless design is an advantage. However, real time trading logic has to maintain its internal state (position, orders, account, etc) and has to act on the changes of them. In AFL scripts this information has to be collected in each execution. Then check for the all possible changes. In case of any state change is detected, it has to act on it. But there are a lot of dependencies. So we end up with huge nested if-else structures. And I still did not talk about delays to wait for thing to happen and error braches. So writing this kind of code in AFL is not that fun. To make it more hard work there are no debugging facilities in AmiBroker. There is no error/exception handling either. This leads to my final problem: debugging and testing real time trading system.

My last problem to note here is testing. Testing the indicators and signaling are ok. I have a reference database that I do not refresh. I develop the indicator and the signaling on it and then I do a backtest with fixed parameters, timeframe, and range using this database. We review the trade list and if it is fine, we save the trade list. Anytime I need to touch the indicators or the signaling, I just rerun the fixed backtest, and compare the new result with reference list. If there are differences we either justify them and save the new results as reference or go back and look for the bug.

Testing utility functions (e.g. converting timenum to string, etc.) is not this simple. There we need to do some unit testing. For this I usually create some AFL script that call the utility functions with different valid and invalid parameters and checks for the results. This would be almost fine, but we cannot be sure that all code paths are tested. There is no code coverage data.

To test real time trading logic is even harder. There is no way (without an exchange simulator) to check code validity. To make it worse the AFL script can have hidden mistyping errors that will be discovered only at times when that particular code path is executed (e.g. a code path can be executed only if we are long, and the trailing stop order is being moved). And it can happen while you are not at the screen. Here comes tracing, logging and screen capture. But that is after the fact that you missed a trade or have a losing one.

All these problems are problems now for those who create complex or real time trading system. When AmiBroker was designed they very likely did not exist! Indicator and signal development is still cool in AFL. Backtesting with AmiBroker is still great.

Using .NET will NOT solve all the problems of trading system development. It certainly makes plug-in development easier, faster, cheaper and even fun. Utility functions created in .NET can be code coverage and unit tested. AFL code is easily converted to .NET code, and .NET code can be debugged. .NET Class library provides a lot of debugging and tracing features for real time trading system developers. By compiling the code the mistyping and type mismatch errors are gone as well.

There are also a lot of new possibilities in hosting .NET runtime inside AmiBroker also. The plug-ins created in .NET can use all the features of .NET Class Library, while AFL scripts can use this plug-ins as if they were AmiBroker's built-in functions.

Happy trading!

.NET for AmiBroker

(Jozsef Toth)