Newbie contemplating making classes vs just sets of functions

 

I am seeking general commentary rather than hard answers.

This is not a question about specific implementation or X > Y > Z, but rather about a general sense of the significant, or potentially significant differences, between organizing a bunch of programming into ordinary function sets, or classes, especially with regard to someone who is new to this that is contemplating which way to go. I may say right now, in the end, I may only end up finalizing my decision the hard way through experience, but I figure I can at least get some ideas here that may help avoid the needless headaches, and only engage in the headaches that are necessary.

I'm still very new to both MQL5 and programming in general, but I've been able to successfully implement some simpler indicator/EA functions. As I move forward in building up my first EA, already with thousands of lines of code, I am struck that organization is the #1 priority. Without very good organizational structure of functions/etc. it becomes increasingly difficult to change/add things. As such, I want to take various things that I do over and over again, and create functions out of them, and perhaps package some of these functions into packages as libraries of include files.

I'm trying to decide whether I want to organize the functions of my EA/etc. into libraries or ordinary functions, classes, or both. Having looked over the CTrade class I am actually somewhat impressed by how it encapsulates all sorts of misc trade functions into 1 overall thing. However, I also wonder whether it would be simpler to just make an include file full of functions like that (not necessarily trade functions, but just sets of related functions in a somewhat analogous manner), except functions specific to my requirements.

Whether I use classes or not, I can take every little thing I do repeatedly, package it into an individual function, or as a base of another function, or a derivative of another function--and then package that into a set of these functions.

The question is, how would it look/feel differently to do it the class way vs the library of functions way. Also, what are the implications of doing it one way vs the other, when it comes to storing/accessing the data of these functions/packages?

Perhaps the advantage of using classes instead of mere function libraries is that if many functions are dependent on the same data, or behave hierarchically, using a class to create an object instance of such a set of functions, might make it easier/convenient to give this function set a place to share data, and it might make it easier/convenient to hierarchize the functions. But maybe that's just a mistaken impression.

I'm not interested in spending the next few weeks/months reading abstract ideas that have nothing to do with my implementations. I'm interested in more brief textual sojourns with the bulk of my time spent either contemplating/planning/writing/drawing ideas about organizing my programmatical functionality, or actually attempting to implement such organizational schemes, whether via ordinary function libraries, classes or both. I find endless reading/following to be mentally taxing and unrewarding, and avoid it unless absolutely necessary. I've been finding the last month spent actually making/doing things far more enjoyable/sustainable than the previous month I spent entirely on lessons which was almost impossible to force myself to do, although, to some degree, necessary.

Trade Operations in MQL5 - It's Easy
Trade Operations in MQL5 - It's Easy
  • www.mql5.com
Almost all traders come to market to make money but some traders also enjoy the process itself. However, it is not only manual trading that can provide you with an exciting experience. Automated trading systems development can also be quite absorbing. Creating a trading robot can be as interesting as reading a good mystery novel.
 
Max0r847:

I am seeking general commentary rather than hard answers.

This is not a question about specific implementation or X > Y > Z, but rather about a general sense of the significant, or potentially significant differences, between organizing a bunch of programming into ordinary function sets, or classes, especially with regard to someone who is new to this that is contemplating which way to go. I may say right now, in the end, I may only end up finalizing my decision the hard way through experience, but I figure I can at least get some ideas here that may help avoid the needless headaches, and only engage in the headaches that are necessary.

I'm still very new to both MQL5 and programming in general, but I've been able to successfully implement some simpler indicator/EA functions. As I move forward in building up my first EA, already with thousands of lines of code, I am struck that organization is the #1 priority. Without very good organizational structure of functions/etc. it becomes increasingly difficult to change/add things. As such, I want to take various things that I do over and over again, and create functions out of them, and perhaps package some of these functions into packages as libraries of include files.

I'm trying to decide whether I want to organize the functions of my EA/etc. into libraries or ordinary functions, classes, or both. Having looked over the CTrade class I am actually somewhat impressed by how it encapsulates all sorts of misc trade functions into 1 overall thing. However, I also wonder whether it would be simpler to just make an include file full of functions like that (not necessarily trade functions, but just sets of related functions in a somewhat analogous manner), except functions specific to my requirements.

Whether I use classes or not, I can take every little thing I do repeatedly, package it into an individual function, or as a base of another function, or a derivative of another function--and then package that into a set of these functions.

The question is, how would it look/feel differently to do it the class way vs the library of functions way. Also, what are the implications of doing it one way vs the other, when it comes to storing/accessing the data of these functions/packages?

Perhaps the advantage of using classes instead of mere function libraries is that if many functions are dependent on the same data, or behave hierarchically, using a class to create an object instance of such a set of functions, might make it easier/convenient to give this function set a place to share data, and it might make it easier/convenient to hierarchize the functions. But maybe that's just a mistaken impression.

I'm not interested in spending the next few weeks/months reading abstract ideas that have nothing to do with my implementations. I'm interested in more brief textual sojourns with the bulk of my time spent either contemplating/planning/writing/drawing ideas about organizing my programmatical functionality, or actually attempting to implement such organizational schemes, whether via ordinary function libraries, classes or both. I find endless reading/following to be mentally taxing and unrewarding, and avoid it unless absolutely necessary. I've been finding the last month spent actually making/doing things far more enjoyable/sustainable than the previous month I spent entirely on lessons which was almost impossible to force myself to do, although, to some degree, necessary.

This is how I look at things, concering MQL.

I think a general approach is first of all to take a look at what is the >set< environment in which the code will be executed, you write. - Lets initially assume, you are talking about the algorithmic trading aspect, and allow me to put this focus on EAs and indicators. - I think this is a curcial prerequisite, as you also could be programming something totally different.

But, for my assumption, I set a few simple rules for me to follow as a design guide and so far this has worked quite in my favor for now.

Lets make some predefinitions. OnCalculate and OnTick are event functions, which will be called, whenever new data is available. - So we are programming a continuous algorithm to work on a datastream.

I design my execution path along the processing of this datastream, all functions interacting with this stream are procedural functions (a bunch of functions, as you referenced them).

Any data that needs to be stored along this processing path, if required beyond the local scope of a function, I organize in object oriented structs or classes.

This approach allows me to make a clear cut between processing logic and data storage or manipulations and transformation.

So I have a set of mqh-include files with structs and classes to handle all the required data organisations, like FIFO, FILO buffers, containers, linked lists, trees. Unions for transformation, bit-storage for flags,. "smart pointers", handler-encapslations to manage lifetime of handles and objects. - None of them can be transfered into a LIB(ex5) file, as we cannot export classes or structs or unions. 

For organizing code, and here I am talking about simple functions like ToString(), LotSizeByMargin() and others, I use namespaces and these functions are all procedural implemented. - So they can all be incapsulated inside a LIB(ex5) and exported from there. I did design these mqh-files in such a way, I can use them directly as #include or use the library file with #import, this gives me flexibility in my projects and insures, my encapuslation is clean. - But thats only my approach. - Others might think differently.

Just to be clear about the scaling of this code-base I maintain for myself. THe current size of my "arsenal" of functions to tackel MQLs sortcommings is currently around 11 MB of source code, and the framework I have built is around 2.5 MB of source code. - So it is scaling quite well for large projects and provides me with all I need.

The framework is purely procedural, the "arsenal" of functions is also purely procedural, only the classes and structs to maintain data are object oriented implemented. - These are the only files, I cannot move to a library(ex5).

For the framework, which implements a standard-api for writing indicators, services and EAs, I implemented a data warehouse which cannot be moved into a library(ex5), so this is source code in mqh-files, by #include.

In the end, I have a framework, that makes massive usage of the functions provided by my "arsenal" or collection of functions, and gives me an environment where I can easily and fast code new strategies.

And I can say, no matter the size of your code-base, if you structure it cleanly, and give some general thoughts on how you implement your functions, you will have blazingly fast code, clean and easy to find functions and a cut between your logic, your requirements and your data.

I for my code base can say, its very fast. I would assume one of the reasons for that is the general code design approach I take for writing functions, separating logic from data, maintaining or caching data, if applicable, keeping executioon paths as deterministic as possible.

The environment I have created by this allows me to compile a strategy as indicator, load it on the chart and get the trading results as if I tested an EA in "OHLC-Mode" in the strategy tester. - And it is faster than the strategy tester. - If I want to have an EA, I coooompile the EA part of the framework, and the strategy is available as EA to me.

The framework and the "function collection" is higly optimized and therefore I dont need to worry about efficiency of my code when implementing a strategy. - Its very straight forward for me.


As an addendum, since January this year, I am implementing the framework as a multi timeframe framework, but the beauty ybout my structure of code-base is, there is no requirement to change any of it. they work all right out of the box for me. - Also the strategies already written for the previous verison of my framework wont need any, or very little change to wirk directly in a multi-timeframe environment.

All in all, I would say, the principal of separating code logic from data, and maintaining the principal of code logic is procedural and data storage is object oriented has served me quite well up to now.

 
Dominik Christian Egert #:

This is how I look at things, concering MQL.

I think a general approach is first of all to take a look at what is the >set< environment in which the code will be executed, you write. - Lets initially assume, you are talking about the algorithmic trading aspect, and allow me to put this focus on EAs and indicators. - I think this is a curcial prerequisite, as you also could be programming something totally different.

But, for my assumption, I set a few simple rules for me to follow as a design guide and so far this has worked quite in my favor for now.

Lets make some predefinitions. OnCalculate and OnTick are event functions, which will be called, whenever new data is available. - So we are programming a continuous algorithm to work on a datastream.

I design my execution path along the processing of this datastream, all functions interacting with this stream are procedural functions (a bunch of functions, as you referenced them).

Any data that needs to be stored along this processing path, if required beyond the local scope of a function, I organize in object oriented structs or classes.

This approach allows me to make a clear cut between processing logic and data storage or manipulations and transformation.

So I have a set of mqh-include files with structs and classes to handle all the required data organisations, like FIFO, FILO buffers, containers, linked lists, trees. Unions for transformation, bit-storage for flags,. "smart pointers", handler-encapslations to manage lifetime of handles and objects. - None of them can be transfered into a LIB(ex5) file, as we cannot export classes or structs or unions. 

For organizing code, and here I am talking about simple functions like ToString(), LotSizeByMargin() and others, I use namespaces and these functions are all procedural implemented. - So they can all be incapsulated inside a LIB(ex5) and exported from there. I did design these mqh-files in such a way, I can use them directly as #include or use the library file with #import, this gives me flexibility in my projects and insures, my encapuslation is clean. - But thats only my approach. - Others might think differently.

Just to be clear about the scaling of this code-base I maintain for myself. THe current size of my "arsenal" of functions to tackel MQLs sortcommings is currently around 11 MB of source code, and the framework I have built is around 2.5 MB of source code. - So it is scaling quite well for large projects and provides me with all I need.

The framework is purely procedural, the "arsenal" of functions is also purely procedural, only the classes and structs to maintain data are object oriented implemented. - These are the only files, I cannot move to a library(ex5).

For the framework, which implements a standard-api for writing indicators, services and EAs, I implemented a data warehouse which cannot be moved into a library(ex5), so this is source code in mqh-files, by #include.

In the end, I have a framework, that makes massive usage of the functions provided by my "arsenal" or collection of functions, and gives me an environment where I can easily and fast code new strategies.

And I can say, no matter the size of your code-base, if you structure it cleanly, and give some general thoughts on how you implement your functions, you will have blazingly fast code, clean and easy to find functions and a cut between your logic, your requirements and your data.

I for my code base can say, its very fast. I would assume one of the reasons for that is the general code design approach I take for writing functions, separating logic from data, maintaining or caching data, if applicable, keeping executioon paths as deterministic as possible.

The environment I have created by this allows me to compile a strategy as indicator, load it on the chart and get the trading results as if I tested an EA in "OHLC-Mode" in the strategy tester. - And it is faster than the strategy tester. - If I want to have an EA, I coooompile the EA part of the framework, and the strategy is available as EA to me.

The framework and the "function collection" is higly optimized and therefore I dont need to worry about efficiency of my code when implementing a strategy. - Its very straight forward for me.


As an addendum, since January this year, I am implementing the framework as a multi timeframe framework, but the beauty ybout my structure of code-base is, there is no requirement to change any of it. they work all right out of the box for me. - Also the strategies already written for the previous verison of my framework wont need any, or very little change to wirk directly in a multi-timeframe environment.

All in all, I would say, the principal of separating code logic from data, and maintaining the principal of code logic is procedural and data storage is object oriented has served me quite well up to now.

This doesn't sound like the beginnings of a foray into programming and algorithmic trading to me. Sounds amazing.
 
Dominik Christian Egert #:

This is how I look at things, concering MQL.

I think a general approach is first of all to take a look at what is the >set< environment in which the code will be executed, you write. - Lets initially assume, you are talking about the algorithmic trading aspect, and allow me to put this focus on EAs and indicators. - I think this is a curcial prerequisite, as you also could be programming something totally different.

But, for my assumption, I set a few simple rules for me to follow as a design guide and so far this has worked quite in my favor for now.

Lets make some predefinitions. OnCalculate and OnTick are event functions, which will be called, whenever new data is available. - So we are programming a continuous algorithm to work on a datastream.

I design my execution path along the processing of this datastream, all functions interacting with this stream are procedural functions (a bunch of functions, as you referenced them).

Any data that needs to be stored along this processing path, if required beyond the local scope of a function, I organize in object oriented structs or classes.

This approach allows me to make a clear cut between processing logic and data storage or manipulations and transformation.

So I have a set of mqh-include files with structs and classes to handle all the required data organisations, like FIFO, FILO buffers, containers, linked lists, trees. Unions for transformation, bit-storage for flags,. "smart pointers", handler-encapslations to manage lifetime of handles and objects. - None of them can be transfered into a LIB(ex5) file, as we cannot export classes or structs or unions. 

For organizing code, and here I am talking about simple functions like ToString(), LotSizeByMargin() and others, I use namespaces and these functions are all procedural implemented. - So they can all be incapsulated inside a LIB(ex5) and exported from there. I did design these mqh-files in such a way, I can use them directly as #include or use the library file with #import, this gives me flexibility in my projects and insures, my encapuslation is clean. - But thats only my approach. - Others might think differently.

Just to be clear about the scaling of this code-base I maintain for myself. THe current size of my "arsenal" of functions to tackel MQLs sortcommings is currently around 11 MB of source code, and the framework I have built is around 2.5 MB of source code. - So it is scaling quite well for large projects and provides me with all I need.

The framework is purely procedural, the "arsenal" of functions is also purely procedural, only the classes and structs to maintain data are object oriented implemented. - These are the only files, I cannot move to a library(ex5).

For the framework, which implements a standard-api for writing indicators, services and EAs, I implemented a data warehouse which cannot be moved into a library(ex5), so this is source code in mqh-files, by #include.

In the end, I have a framework, that makes massive usage of the functions provided by my "arsenal" or collection of functions, and gives me an environment where I can easily and fast code new strategies.

And I can say, no matter the size of your code-base, if you structure it cleanly, and give some general thoughts on how you implement your functions, you will have blazingly fast code, clean and easy to find functions and a cut between your logic, your requirements and your data.

I for my code base can say, its very fast. I would assume one of the reasons for that is the general code design approach I take for writing functions, separating logic from data, maintaining or caching data, if applicable, keeping executioon paths as deterministic as possible.

The environment I have created by this allows me to compile a strategy as indicator, load it on the chart and get the trading results as if I tested an EA in "OHLC-Mode" in the strategy tester. - And it is faster than the strategy tester. - If I want to have an EA, I coooompile the EA part of the framework, and the strategy is available as EA to me.

The framework and the "function collection" is higly optimized and therefore I dont need to worry about efficiency of my code when implementing a strategy. - Its very straight forward for me.


As an addendum, since January this year, I am implementing the framework as a multi timeframe framework, but the beauty ybout my structure of code-base is, there is no requirement to change any of it. they work all right out of the box for me. - Also the strategies already written for the previous verison of my framework wont need any, or very little change to wirk directly in a multi-timeframe environment.

All in all, I would say, the principal of separating code logic from data, and maintaining the principal of code logic is procedural and data storage is object oriented has served me quite well up to now.


I think I'm going to re-read that every once in a while and see what parts of it stick out at me as I move forward :D What I find most interesting is the separation of logic from data, and the object-oriented data storage.

Also I have noticed that already in a couple cases I wasn't really sure whether I wanted to do something in an indicator or EA, as I figured either one would work. For example I had an indicator generate a primitive rudimentary signal and put it in a buffer which would be read by the EA, rather than do that stuff in the EA, mainly because I wanted the indicator to show that stuff visually, and because I didn't want to get bogged down in that stuff in the EA. I also considered the idea that an indicator could just draw out trade triggers visually on a chart to inspect at leisure, being more efficient than doing a visual playback if wanting to see the details of how it actually plays out in the chart rather than just trade performance. On the other hand, supposedly it's more efficient to do everything in the EA, to the minimal degree required, when the time comes for full optimization. This of course would support your method of making stuff that can be used for both.

Quite frankly, trying to imagine deliberately structuring everything with this far-seeing view doesn't just make my head hurt, it makes me feel like I never had a functioning brain to begin with. I will probably have to proceed stupidly and blindly, to some degree, and integrate little bits and bobs of these concepts over time, as they start to show themselves to be the potential cures to my increasing miseries :D

 
Max0r847 #:


I think I'm going to re-read that every once in a while and see what parts of it stick out at me as I move forward :D What I find most interesting is the separation of logic from data, and the object-oriented data storage.

Also I have noticed that already in a couple cases I wasn't really sure whether I wanted to do something in an indicator or EA, as I figured either one would work. For example I had an indicator generate a primitive rudimentary signal and put it in a buffer which would be read by the EA, rather than do that stuff in the EA, mainly because I wanted the indicator to show that stuff visually, and because I didn't want to get bogged down in that stuff in the EA. I also considered the idea that an indicator could just draw out trade triggers visually on a chart to inspect at leisure, being more efficient than doing a visual playback if wanting to see the details of how it actually plays out in the chart rather than just trade performance. On the other hand, supposedly it's more efficient to do everything in the EA, to the minimal degree required, when the time comes for full optimization. This of course would support your method of making stuff that can be used for both.

Quite frankly, trying to imagine deliberately structuring everything with this far-seeing view doesn't just make my head hurt, it makes me feel like I never had a functioning brain to begin with. I will probably have to proceed stupidly and blindly, to some degree, and integrate little bits and bobs of these concepts over time, as they start to show themselves to be the potential cures to my increasing miseries :D

Dont worry, you will figure it out. - Ill give you two files. - They surely do not compile, but they show you how it looks like, and maybe you get inspired by this somehow.

File MQLplusCharting.mqh is the main strategy, this file is compiled either as indicator or as an EA. - You can see, its simple to code a strategy in this framework.

Then there is MQLplusTrader.mqh, this file is exclusive for the EA, and will only be part of the EAs code. Here you can see how I handle specifics inside an EA.

The content is "as is", there is not really a use case for you, and they are already old. - I played around with some stuff in there, so please dont judge me on the content.....

Any references to "Lib Bali" are references to the framework, thats what I called it.
Files:
 
Dominik Christian Egert #:

Dont worry, you will figure it out. - Ill give you two files. - They surely do not compile, but they show you how it looks like, and maybe you get inspired by this somehow.

File MQLplusCharting.mqh is the main strategy, this file is compiled either as indicator or as an EA. - You can see, its simple to code a strategy in this framework.

Then there is MQLplusTrader.mqh, this file is exclusive for the EA, and will only be part of the EAs code. Here you can see how I handle specifics inside an EA.

The content is "as is", there is not really a use case for you, and they are already old. - I played around with some stuff in there, so please dont judge me on the content.....

Any references to "Lib Bali" are references to the framework, thats what I called it.

I look forward to poking around with this stuff next time I'm in bigthink galaxy brain mode. I definitely don't care about the specific content. Probably much like you, I am extremely individually picky about what I do and how I do it, especially when it comes to technical analysis, but also when it comes to how I want to code/arrange things. My brain works in certain ways and sometimes I look at someone else's code and it's like I have an allergic reaction :D It's the ideas about structuring/organization that I'm most interested in, and seeing how other people arrange things visually as well. Sometimes all it takes is just 1 cute little trick to make things much easier and more robust. ;)

 

I was never formally trained as a developer, but I started doing development work about 40 years ago, and have led various dev and consulting teams. As a consequence of that, I find I tend to be incredibly impatient at getting to a solution — just get it done for the sake of proof of concept or personal use. But I know OOP and good system architecture. I just don't want to waste time on that overhead when I'm trying to figure out if something is even worth pursuing or not.

Over time, within a domain, you start seeing things that merit reuse, and increasing polymorphism. So I go back and refactor, and the next time, I have that in my toolkit.

That approach works well for me in this domain. I'm writing trading scripts for my own personal use, not a portfolio manager for a hedge fund. So I'll continue the approach of doing it the most expedient way, until such time as the pain of not refactoring exceeds the pain of refactoring.

 
Scott Allen #:

I was never formally trained as a developer, but I started doing development work about 40 years ago, and have led various dev and consulting teams. As a consequence of that, I find I tend to be incredibly impatient at getting to a solution — just get it done for the sake of proof of concept or personal use. But I know OOP and good system architecture. I just don't want to waste time on that overhead when I'm trying to figure out if something is even worth pursuing or not.

Over time, within a domain, you start seeing things that merit reuse, and increasing polymorphism. So I go back and refactor, and the next time, I have that in my toolkit.

That approach works well for me in this domain. I'm writing trading scripts for my own personal use, not a portfolio manager for a hedge fund. So I'll continue the approach of doing it the most expedient way, until such time as the pain of not refactoring exceeds the pain of refactoring.

A counterargument to your approach could be to see the difference in time it takes for a German car manufacturer and a Chinese to develop a new car. Germans have reduced the time from somewhat 10 years down to three to four years. While the Chinese are below one year.

Which car do you trust more? A VW or a Hongguang.