252 lines
9.4 KiB
MQL5
252 lines
9.4 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| CTradeSignal.mqh |
|
||
|
//| Copyright 2025, MetaQuotes Ltd. |
|
||
|
//| https://www.mql5.com |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#property copyright "SoloTrade Official, Solomon"
|
||
|
#property link "https://www.mql5.com/en/users/SoloTradeOfficial"
|
||
|
#property version "1.00"
|
||
|
#property description "THE WORLD MOST INTELLIGENT FOREX AI/ALGO BOTS EVER IN"
|
||
|
"HUMAN HISTORY OF FINTECH, BY SOLOMON ESHUN"
|
||
|
"\nTrading Bots in MQL5"
|
||
|
|
||
|
// Scope Resolution Operator `::`
|
||
|
// --- DECLARATION ---
|
||
|
// This part is like the public menu. It tells us WHAT the class can do.
|
||
|
|
||
|
class CTradeSignal {
|
||
|
private:
|
||
|
string m_symbol;
|
||
|
int m_magic_number;
|
||
|
|
||
|
public:
|
||
|
// Constructor declaration
|
||
|
CTradeSignal(string symbol, int magic_number);
|
||
|
|
||
|
// Method declaration
|
||
|
void CheckSignal();
|
||
|
};
|
||
|
|
||
|
|
||
|
// --- DEFINITION / IMPLEMENTATION ---
|
||
|
// This part is the kitchen. It's HOW the work gets done.
|
||
|
// Because this code is outside the class { } block, we MUST use ::
|
||
|
|
||
|
// Definition for the constructor
|
||
|
CTradeSignal::CTradeSignal(string symbol, int magic_number) {
|
||
|
m_symbol = symbol;
|
||
|
m_magic_number = magic_number;
|
||
|
Print("Trade Signal object created for ", m_symbol);
|
||
|
}
|
||
|
|
||
|
// Definition for the CheckSignal method
|
||
|
void CTradeSignal::CheckSignal() {
|
||
|
// Some complex logic to check for a trade signal...
|
||
|
Print("Checking for a signal on ", m_symbol, " with magic number ", m_magic_number);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
|
||
|
// NOTES BELOW
|
||
|
//You are asking fantastic questions that get to the heart of Object-Oriented Programming (OOP) design. Let's break down both of these concepts.
|
||
|
//
|
||
|
//---
|
||
|
//
|
||
|
//### Part 1: The Scope Resolution Operator (`::`)
|
||
|
//
|
||
|
//This is a syntax tool, a way of giving the compiler an exact address for a piece of code.
|
||
|
//
|
||
|
//**The Core Idea:** The `::` operator tells the compiler, "The function I am defining on the left of the `::` belongs to the class I am naming on the right." It resolves the *scope* of the function.
|
||
|
//
|
||
|
//**Analogy: The Office Building**
|
||
|
//
|
||
|
//Imagine you have a large office building (your entire program). The building has several departments: Sales, Marketing, and Engineering (these are your classes).
|
||
|
//
|
||
|
//Each department has a manager named "John."
|
||
|
//
|
||
|
//* `Sales::John`
|
||
|
//* `Marketing::John`
|
||
|
//* `Engineering::John`
|
||
|
//
|
||
|
//If you just shout "John!", nobody knows who you're talking about. You need to be specific. The `::` is how you specify which "department" (class) the "person" (function) belongs to.
|
||
|
//
|
||
|
//So, `Car::Car(...)` means "I am defining the `Car` constructor that belongs to the `Car` class."
|
||
|
//
|
||
|
//#### Why Do We Need This?
|
||
|
//
|
||
|
//The main reason is for **code organization**. It's considered very good practice to separate a class's *declaration* from its *definition (or implementation)*.
|
||
|
//
|
||
|
//1. **The Declaration (The "What"):** This goes in a header file (e.g., `Car.mqh`). It's like the table of contents for your class. It tells the world what the class is named and what public functions it has, but not *how* they work.
|
||
|
//
|
||
|
//2. **The Definition (The "How"):** This can go in the same file (usually below the declaration) or a separate `.cpp` file in larger projects. This is where you write the actual code for each function. Because this code is now *outside* the `class { ... }` block, you must use the scope resolution operator (`::`) to tell the compiler which class each function belongs to.
|
||
|
//
|
||
|
//#### MQL5 Example:
|
||
|
//
|
||
|
//Let's see this in action with a `CTradeSignal` class.
|
||
|
//
|
||
|
//**File: `CTradeSignal.mqh`**
|
||
|
//
|
||
|
//```mql5
|
||
|
//// --- DECLARATION ---
|
||
|
//// This part is like the public menu. It tells us WHAT the class can do.
|
||
|
//
|
||
|
//class CTradeSignal
|
||
|
//{
|
||
|
//private:
|
||
|
// string m_symbol;
|
||
|
// int m_magic_number;
|
||
|
//
|
||
|
//public:
|
||
|
// // Constructor declaration
|
||
|
// CTradeSignal(string symbol, int magic_number);
|
||
|
//
|
||
|
// // Method declaration
|
||
|
// void CheckSignal();
|
||
|
//};
|
||
|
//
|
||
|
//
|
||
|
//// --- DEFINITION / IMPLEMENTATION ---
|
||
|
//// This part is the kitchen. It's HOW the work gets done.
|
||
|
//// Because this code is outside the class { } block, we MUST use ::
|
||
|
//
|
||
|
//// Definition for the constructor
|
||
|
//CTradeSignal::CTradeSignal(string symbol, int magic_number)
|
||
|
//{
|
||
|
// m_symbol = symbol;
|
||
|
// m_magic_number = magic_number;
|
||
|
// Print("Trade Signal object created for ", m_symbol);
|
||
|
//}
|
||
|
//
|
||
|
//// Definition for the CheckSignal method
|
||
|
//void CTradeSignal::CheckSignal()
|
||
|
//{
|
||
|
// // Some complex logic to check for a trade signal...
|
||
|
// Print("Checking for a signal on ", m_symbol, " with magic number ", m_magic_number);
|
||
|
//}
|
||
|
//```
|
||
|
//
|
||
|
//By separating the "what" from the "how," your class declaration at the top becomes very clean and easy to read, while the complex logic is neatly organized below.
|
||
|
//
|
||
|
//---
|
||
|
//
|
||
|
//### Part 2: Composition ("Has-A" Relationship)
|
||
|
//
|
||
|
//This is a powerful design pattern. You've already learned about Inheritance, which creates an "Is-A" relationship (`A CMACrossoverSignal` **is a** `CSignal`).
|
||
|
//
|
||
|
//**Composition creates a "Has-A" relationship.**
|
||
|
//
|
||
|
//**The Core Idea:** Instead of a class inheriting features, it is *composed* of other objects. It holds other objects inside it as member variables.
|
||
|
//
|
||
|
//**Analogy: The Car (Again!)**
|
||
|
//
|
||
|
//A `Car` is a perfect example of composition.
|
||
|
//
|
||
|
//* A `Car` **is not** an `Engine`.
|
||
|
//* A `Car` **is not** a `Wheel`.
|
||
|
//* Instead, a `Car` **has an** `Engine`.
|
||
|
//* A `Car` **has** four `Wheels`.
|
||
|
//* A `Car` **has a** `Transmission`.
|
||
|
//
|
||
|
//The `Car` class coordinates the work of all its component parts. When you press the accelerator in the `Car`, the `Car` object tells its `Engine` object to increase RPMs, which in turn tells the `Transmission` object to engage a gear, which tells the `Wheel` objects to turn.
|
||
|
//
|
||
|
//#### MQL5 Example: An Expert Advisor Composed of Parts
|
||
|
//
|
||
|
//Let's model an EA. An EA might be composed of a signal generator, a risk manager, and a trade executor.
|
||
|
//
|
||
|
//**Step 1: Define the "Part" Classes**
|
||
|
//
|
||
|
//We'll use the `CRiskManager` from our Abstraction example and a simplified `CTradeExecutor`.
|
||
|
//
|
||
|
//```mql5
|
||
|
//// (Assuming CRiskManager class is defined as in the previous example)
|
||
|
//
|
||
|
//class CTradeExecutor
|
||
|
//{
|
||
|
//public:
|
||
|
// void ExecuteBuy(string symbol, double lots)
|
||
|
// {
|
||
|
// Print("EXECUTOR: Placing BUY order for ", lots, " lots on ", symbol);
|
||
|
// // Real MQL5 OrderSend() logic would go here
|
||
|
// }
|
||
|
//};
|
||
|
//```
|
||
|
//
|
||
|
//**Step 2: Define the "Whole" Class using Composition**
|
||
|
//
|
||
|
//The `CExpertAdvisor` class will *contain* objects of the other classes as member variables.
|
||
|
//
|
||
|
//```mql5
|
||
|
//// Include the files for the parts
|
||
|
//#include "CRiskManager.mqh"
|
||
|
//#include "CTradeExecutor.mqh"
|
||
|
//// (Assuming CTradeSignal from above is also available)
|
||
|
//
|
||
|
//class CExpertAdvisor
|
||
|
//{
|
||
|
//private:
|
||
|
// // --- COMPOSITION HAPPENS HERE ---
|
||
|
// // The EA "has-a" signal, a risk manager, and an executor.
|
||
|
// CTradeSignal m_signal;
|
||
|
// CRiskManager m_risk_manager;
|
||
|
// CTradeExecutor m_trade_executor;
|
||
|
//
|
||
|
//public:
|
||
|
// // The EA's constructor initializes its component parts
|
||
|
// CExpertAdvisor(string symbol, int magic_number) : m_signal(symbol, magic_number),
|
||
|
// m_risk_manager(1.0, 5), // 1% risk, 5 trades max
|
||
|
// m_trade_executor()
|
||
|
// {
|
||
|
// Print("Expert Advisor object created and ready.");
|
||
|
// }
|
||
|
//
|
||
|
// // The EA's main logic function
|
||
|
// void OnTick()
|
||
|
// {
|
||
|
// // The EA delegates work to its parts.
|
||
|
// // 1. It asks its signal component for a signal.
|
||
|
// // m_signal.CheckSignal(); // Pretend this returns a trade direction
|
||
|
//
|
||
|
// ENUM_TRADE_DIRECTION tradeDirection = GetSignalFromSomewhere(); // Fake signal
|
||
|
//
|
||
|
// if (tradeDirection != TRADE_DIRECTION_NONE)
|
||
|
// {
|
||
|
// // 2. It asks its risk manager component if a trade is allowed.
|
||
|
// if (m_risk_manager.isTradeAllowed(30.0)) // 30 pips SL
|
||
|
// {
|
||
|
// // 3. If everything is OK, it tells its trade executor to place the trade.
|
||
|
// m_trade_executor.ExecuteBuy(_Symbol, 0.1);
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// // Fake function for demonstration
|
||
|
// ENUM_TRADE_DIRECTION GetSignalFromSomewhere() { return TRADE_DIRECTION_BUY; }
|
||
|
//};```
|
||
|
//
|
||
|
//**Step 3: Using the Composed Object**
|
||
|
//
|
||
|
//```mql5
|
||
|
//// In your main .mq5 file
|
||
|
//
|
||
|
//#include "CExpertAdvisor.mqh"
|
||
|
//
|
||
|
//// Create the main EA object
|
||
|
//CExpertAdvisor MyEA("EURUSD", 12345);
|
||
|
//
|
||
|
//// The main OnTick function simply delegates all work to our EA object.
|
||
|
//void OnTick()
|
||
|
//{
|
||
|
// MyEA.OnTick();
|
||
|
//}
|
||
|
//```
|
||
|
//
|
||
|
//### Summary: Composition vs. Inheritance
|
||
|
//
|
||
|
//| Feature | Inheritance ("Is-A") | Composition ("Has-A") |
|
||
|
//| :--- | :--- | :--- |
|
||
|
//| **Relationship** | A derived class is a specialized version of its base class. | An object is built from other, independent objects. |
|
||
|
//| **Flexibility** | Static. The relationship is fixed when you compile the code. | Highly flexible. You can often change the "parts" at runtime. |
|
||
|
//| **Coupling** | Tightly coupled. A change in the base class can break all derived classes. | Loosely coupled. The "whole" only cares about the public interface of its "parts". |
|
||
|
//| **When to Use** | When you can say "Type B is a type of Type A". (A `Toyota` is a `Car`). | When you can say "Type A has a Type B". (A `Car` has an `Engine`). |
|
||
|
//
|
||
|
//Generally, modern programming advice is to **"prefer composition over inheritance."** It leads to more flexible, scalable, and maintainable code, just like you saw with the `CExpertAdvisor` example.
|