Welcome to NexusFi: the best trading community on the planet, with over 150,000 members Sign Up Now for Free
Genuine reviews from real traders, not fake reviews from stealth vendors
Quality education from leading professional traders
We are a friendly, helpful, and positive community
We do not tolerate rude behavior, trolling, or vendors advertising in posts
We are here to help, just let us know what you need
You'll need to register in order to view the content of the threads and start contributing to our community. It's free for basic access, or support us by becoming an Elite Member -- see if you qualify for a discount below.
-- Big Mike, Site Administrator
(If you already have an account, login at the top of the page)
I've decided to write my own journaling software - as a study for SierraChart. This will let me journal my trades in real time, and make journaling a natural part of my workflow rather than a chore or afterthought.
I will document my progress in this forum post:
My first experience of ACSIL and getting started with C++
The concepts, design and high level architecture
Problems encountered, solutions and workarounds
Code examples
Whilst it will be part technical (C++, ACSIL and general programming concepts), I will also discuss how I see and trade the market, and the information I want to record to make me a better trader. Hopefully this will make it interesting for general traders that have no interest in SierraChart or coding.
My background
I've been a programmer for over 30 years. I started writing assembly language on 8-bit 6502 and Z80 CPUs, and most recently I've written quantitative analysis software using Python and automated trading bots for InteractiveBrokers' TWS.
I've been a daytrader for the past 3 years. I learnt to daytrade during the last crypto boom and now I mainly trade ES futures. I am a discretionary trader and do not follow a set system. I do not use indicators and trade purely based on fomo market structure and order flow.
The initial goal
I currently use Jigsaw Journalytix. The statistic I most care about is Maximum Adverse Excursion (MAE). However, for some reason Journalytix does not calculate this accurately. For example, sometimes I know a trade has gone 2-3 ticks against me on initial entry, but Journalytix will often report 0 MAE.
I find MAE important because it tells me if I can bring my stop closer. The closer I can bring my stop to entry, the better my risk/reward.
Journalytix cannot answer these questions because it only records MAE and MFE from entry to exit. I need to calculate the potential MAE and MFE on either side of my entry and exit as well, to see if an earlier entry or a later exit would be profitable.
Basic plan
I'm not really a planner and prefer to make things up as I go along. However, this was the basic plan when I started:
Pick an IDE and get familiar with C++
Understand ACSIL concepts, get the API, look at sample code
Write a simple "Hello, world!" study
This will likely grow into a larger project, so build a workflow and framework for SierraChart indicators
Come up with a high level software design; classes, data structures. I want the business logic to be kept separate from the SierraChart integration and User Interface. If I move to a different platform in the future, I'll only need to rewrite the platform-specific parts.
Figure out how best to integrate the journal controls in SierraChart so that operation becomes part of my natural trading workflow and not an afterthought or chore.
If I was a really advanced programmer like this guy on YouTube, I would write my code in Microsoft Word. However, I decided to play safe and stick to the more traditional method of using an IDE (Integrated Development Environment). SierraChart indicators are written in C++, so I need an IDE for C++.
Microsoft Visual Studio (free)
JetBrains CLion (not free)
Visual Studio is often a default option but it feels too much like work to me. This is supposed to be a fun project. So I decided to splash out on JetBrains CLion. I already use JetBrains' Python IDE and I like it a lot, so it was a no brainer for me to just go with CLion.
Java/C#/Python assign by reference as default, and C++ assigns by value as default.
Pseudocode:
In Java/C#/Python, we end up with one actual Cat with two names ("a" and "b"). So you could feed "a" or "b" and it would be the same end result as they both refer to the same actual object. In C++ we end up with two actual Cats (one called "a" and one called "b"). "a" is a different actual object than "b". So if you feed "a", "b" will still be hungry.
If you want c++ to pass by reference, you can use the & symbol to pass by reference, or you can use the * to specify a pointer to the memory location of the object. Pass by reference and Pass by pointer are fast because a copy does not need to be made. However, if you're sending your object to a function, you need to trust that function doesn't do stuff to your object that you don't want. c++ has the 'const' keyword, which guarantees the function will treat your object as read only, and not make any changes.
If the object you want to pass to a function is no longer needed by your code, you can "move" it. This is functionally equivalent to passing by value, except that instead of sending a copy of your object, your actual object is sent.
In summary, there are 4 ways to pass objects around:
By Value - object is copied. Safe, but slow.
By Reference (&) - the actual object is passed rather than a copy. This is fast. The 'const' keyword states the object won't be modified.
By Pointer (*) - a pointer to a memory location containing the object is passed.
By Move - this is like By Value except the copy doesn't happen; your object is just given to the function. This only works if the calling code no longer needs the object.
It is possible that a Pointer points to an object that has subsequently been removed from memory. This can cause a program crash. It is up to you to make sure this doesn't happen. Also, if you create objects on Heap memory, it is up to you to delete them. Otherwise you will get a memory leak.
Once you understand these concepts and differences, everything else is just a matter of stackoverflow syntax.
I really like C++. A lot. I'm not sure it would have been my first choice for the F35 Joint Strike Fighter though.
I want to be able to differentiate between a longer swing position and an interim scalp. For example, I may hold a short with a target of 40 ticks, and during that time I may take a long for 8 ticks. I view this as two completely separate trades.
I also want to be able to support scale-in/scale-out.
I have come up with names for the main classes and data structures:
Journal - this is the highest level object and contains all data for all time.
Playbook - a collection of strategies.
Strategy - a type of trade idea, e.g. a chart pattern, type of order flow, or other event that may be tradeable. A strategy may require a certain type of market condition to be valid.
Market Character - classification of market condition.
Opportunity - when a strategy has been identified.
Orderfill - Orderfills are allocated to an opportunity.
Session - a defined period of time that neatly groups opportunities for review. For a daytrader, this might be 0930-1600 for each trading day.
I have opted not to use the term 'Trade', and instead chose 'Opportunity'. Trade is already used to mean a single transaction between two parties. For example, if you watch the Time and Sales, each entry is a Trade consisting of time, volume and price. I would find it confusing to reuse the term Trade in this context.
It is possible that I would identify opportunities on the chart and not execute them, and I can collect stats on that as well.
The first issue I encountered with SierraChart was actually getting my code to compile. SierraChart was designed to use the C++ compiler provided with the Build Tools from Visual Studio 2015. However, it doesn't work with 2017 or 2019. This post on the SC Board seems to be related to the same issue, but doesn't provide a solution.
When I ask SierraChart to compile and install my code, it creates and runs a batch file called VisualCCompile.Bat. VisualCCompile.Bat in turn calls vcvarsall.bat which configures the build environment ready for compiling. However, the location of vcvarsall.bat has changed between 2015 and 2019 and SierraChart is still looking in the old location.
SierraChart checks an environment variable called VS140COMNTOOLS that defines where the location of vcvarsall.bat is located. So it should just be a case of changing the environment variable from the 2015 default to the new location required by 2019: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat. Unfortunately this doesn't work either, because SierraChart incorrectly tries to insert a /vc/ at the end of the path - helpful for 2015 but not for 2019.
I opened this support ticket with SierraChart about the issue and it seems they are going to fix the issue in the next release. For now, I have created a dummy vcvarsall.bat file where SierraChart expects to find it, and I point that to the vcvarsall.bat where Microsoft actually puts it.
As I'm developing a larger project, I want to organise my code into several files. SierraChart allows this, but the interface is not very intuitive. You need to specify all the files to compile in a single line, and then the resulting .dll is named after the first file in the line, regardless of what you actually want it to be called. I opened this support ticket.
As a workaround, I'm asking SierraChart to compile a single .cpp file, and that .cpp file includes all the other files in my project.
Organising my project
I've come up with a file structure which seems to work quite nicely with SierraChart:
The master myAwesomeStudyCollection.cpp file looks like this:
I spent some time looking at the different testing frameworks for C++.
Google Test
This was the first framework I looked at, but I found it large and cumbersome. I decided to avoid Google Test for similar reasons that I avoided Visual Studio. I wanted something that was header only, so I could simply drop the source files into my folder structure.
The advantage of Google Test is it allows assertions and exceptions to be caught. But for this project, I won't need this functionality.
Doctest
This was actually my preferred choice, but I couldn't get it to work under CLion. It turns out Doctest had released a new version, but CLion hadn't updated their code yet, so it was necessary to modify the version number of the Doctest code for things to work. I don't like issues and workaround like that, so I decided not to use DocTest. I think this is more an issue with CLion that Doctest, and I would probably have used Doctest otherwise.
Catch2
I realised that the person who wrote Catch2 (Phil Nash) is actually a staff member and advocate for CLion. So this pretty much sealed the deal; I'm unlikely to get better test integration with my IDE than this.
Sketching out the user interface
I've been thinking about how I actually want the User Interface within SierraChart to operate. The easiest method would be to use Hotkeys to select the different orderfills and opportunities. When SierraChart detects a keypress it will call the study along with the keycode pressed. So this would be ideal to begin and get things going with minimum coding so I can test the concept.
The initial plan is to use the numeric keypad left/right to select an orderfill, and up/down to select an opportunity. I'll use Enter to assign the orderfill to the opportunity.
SierraChart already displays orderfills as small triangles (Trade menu > Show Order Fills) so I will use the left/right hotkeys to scroll through each orderfill. A yellow circle will highlight the selected orderfill.
Operational modes
Trying to envisage how this would work in my head, I see three states:
Clean - This hides everything.
Assign - This is when I'm mapping an orderflow to an opportunity.
View - This is when I'm viewing an opportunity and want to see stats such as time in trade, average entry price, MAE/MFE, P&L, risk, etc.
Scrolling through the orderfills should be straightforward as they are ordered according to timestamp.
Scrolling through the opportunities will be slightly more complex as the timestamp order of each opportunity will change depending on the orderfills allocated to it.
In addition to scrolling through all opportunities, I want to also include an "Add new" opportunity, and an "Unassigned" opportunity, which shows stats for any orderfills that have not yet been assigned.
A natural order to scroll through opportunities would seem to be:
earliest > .. > latest > addNew > unassigned
However, I don't know if this is going to be the right choice until I can try it for real.
Code
I'll use the State design pattern to process the hotkeys differently for each state. I've put together this outline and commented the objectives so I don't forget. After breakfast I'll try and get this working.