避免术语混淆
TimeFRAME 是业界普遍接受的术语,用于表示市场事件流的“基于时间的框架”,并且几十年来一直将这种含义标准化。
由于自然时间流中与周末相关的间隙以及上述任务定义的性质,在下面的代码-sn-p 中,确实在多个 TimeFRAME 层上并行存在许多与 TimeFRAME 相关的操作(包括PERIOD_D1、PERIOD_H1 并隐藏PERIOD_CURRENT 依赖项(unknown(隐式),因此完全避免使用),以便允许指针计数和后退索引更新(^PTR->TimeSERIES)。
因此,在整个进一步开发过程中,让我们在给定的任务定义下使用 aGreenBOX 的另一个术语,并以不同的方式调用 aTimeDOMAIN 绑定属性 - aTimeWINDOW 和 al(但不是 TimeFRAME ,好吗?)
参数化
最简单的形式是使用下面所述的extern-s 集合。值得注意的是,extern 构造函数是危险的,以防您的 GUI 层应用程序变得更加智能和复杂,并且如果它直接连接到 XTOs ( eX ecute-Trade-O操作)。
#property strict
extern int aGreenBoxWindow_HOUR__ENDs = 7; // aTimeWINDOW.ends <<- 05:00 - 07:00 [GMT-ABCD]
extern int aGreenBoxWindow_HOURs_WIDE = 2; // aTimeWINDOW.width
extern int aGreenBoxWindow_nDAYs_BACK = 4; // aTimeWINDOW.repeatDays
int aCallLockPTR = 0;
string anObjNamePREFIX = "aGreenBOX.id=";
警告
对于基于 MT4 的实时增强交易服务,其中 XTO 操作自动绑定/挂钩到某些 GUI 层元素(M 的 Visual-part VC-triade ),extern 构造函数绑定变量必须避免,因为它们的值的任何变化(由于 MT4 架构设计)都会导致实时增强服务的 Model 和 Controller 部分中的重置和不可重入冲突以及此类交易服务对使用和 XTO。
没有extern-s 的增强交易服务参数化
为了实时操作的增强交易服务,有更好(和更安全)的方法来避免extern 对正在运行的服务的破坏性影响。除了其他我最喜欢使用进程到进程/分布式计算消息传递之外,这主要使您的 MT4-Terminal 成为基于私有云的交易基础设施和您的基于MQL4 的 EA 中的节点开始在交响乐团中演奏,与其他编排乐器一起演奏(无论是 AI/ML-NeuralNetwork 决策计算过程,还是用于投资组合优化量化模型的基于 GPU 的协方差矩阵评估器,简单地说,像这样的任何东西都可以"direct" / "command" an MQL4-process "inside" MT4-终端以平滑、不间断和实时、非阻塞、完全异步的方式,不是吗听起来很吸引人?Yes, it does! 查看this 一次大约 1 [ms] 或更短时间
一个简单的解决方案 - CPU 有效的低优先级方法示例
一旦您进入 UI 设计领域,您的(最初隐藏的)问题称为 UI 控制循环和整体 UI 响应性(UI 响应您的 MMI(Man-Machine-Interface)和外部“输入”流(鼠标单击/鼠标移动/鼠标拖放/aMarketEVENT/等)。
必须实施合理的监管,以避免对重复性任务的低效调用,这些调用不会给 XTO/MVC 优先/MVC 延迟视觉部分重绘操作带来任何新内容。
充分尊重 Joseph 的建议,将 UI 进程作为OnTick()blocking-task 直接挂起到每个 TickArrivalEVENT 原则上是可行的,但是在生产级软件中对于 XTO 来说都是致命的危险,而且 CPU/内存访问/db.POOL 资源浪费的处理能力(通常需要用于其他任务)
int init(){
// ------------------------------------------- // ------------------------
aGreenBoxWINDOWs_Update(); // .init
aCallLockPTR = iBars( NULL, PERIOD_H1 ); // .set a CPU-clock saving LOCK
// ------------------------------------------- // ------------------------
}
int start(){
// ------------------------------------------- // -----------------
// HIGH-PRIORITY OPERATIONS
// ...
// ..
// .
// ||||||||||||||||||||||||||||||||||||||||||| // |||||||||||||||||
if ( iBars( NULL, PERIOD_H1 ) // .TEST
!= aCallLockPTR
){
aGreenBoxWINDOWs_UpdateJusTheLiveOne(); // .UPD GUI
aCallLockPTR = iBars( NULL, PERIOD_H1 ); // .SET PTR
}
else {// ///////////////////////////////////// // .UPD GUI in .id=1
// in case LowestLow or HighestHigh inside the Live part of
// aGreenBOX "aGreenBOX.id=1"
// was moved:
// aGreenBoxWINDOW_UpdateJustTheLiveOne();
// re-lock Hi/Lo_LOCKs // .UPD LOCKs
}
}
用于增强 Visual MVC 部分的 aGreenBOX 魔法
void aGreenBoxWINDOWs_Update(){
int static aGreenBoxWindow_Duration_SECs = aGreenBoxWindow_HOURs_WIDE
* PeriodSeconds( PERIOD_H1 );
int aGreenBoxWindow_H1Offset_ENDs = TimeHour( TimeCurrent() )
- aGreenBoxWindow_HOUR__ENDs;
if ( aGreenBoxWindow_H1Offset_ENDs < 0 ){
aGreenBoxWindow_H1Offset_ENDs+= 24;
}
datetime aGreenBoxWindow_DATETIME_ENDs = iTime( NULL,
PERIOD_D1,
0
)
+ aGreenBoxWindow_HOUR__ENDs
* PeriodSeconds( PERIOD_H1 );
if ( aGreenBoxWindow_DATETIME_ENDs
- aGreenBoxWindow_Duration_SECs > iTime( NULL,
PERIOD_H1,
0
)
){
aGreenBoxWindow_DATETIME_ENDs = iTime( NULL,
PERIOD_D1,
1
)
+ aGreenBoxWindow_HOUR__END
* PeriodSeconds( PERIOD_H1 );
}
for (
//----------------------------------------------- // --------------------
int anObjIDX = 1, // loop-pre-setting(s)
string anObjNAME = anObjNamePREFIX + "1", // var(s)=value(s) ( life-span only "inside" for(){...}-constructor in MQL4.5+ ...)
int anObjENDs = aGreenBoxWindow_DATETIME_ENDs;
//----------------------------------------------- // --------------------
anObjIDX <= aGreenBoxWindow_nDAYs_BACK; // loop-pre-condition
//----------------------------------------------- // --------------------
// loop-post-update(s)
anObjIDX++, // IDX
anObjNAME = anObjNamePREFIX + anObjIDX, // NAME
anObjENDs = iTime( NULL, // ENDs
PERIOD_D1,
anObjIDX
)
+ PeriodSeconds( PERIOD_H1 )
* aGreenBoxWindow_HOUR__ENDs,
aGreenBoxWindow_H1Offset_ENDs+= 24 // ENDs ^H1
//----------------------------------------------- // --------------------
){ // loop-body:
if ( ObjectFind( anObjNAME ) < 0 ){ // !found .ADD
ObjectCreate( anObjNAME, OBJ_RECTANGLE, 0,
aGreenBoxWindow_DATETIME_ENDs,
iHigh( NULL,
PERIOD_H1,
iHighest( NULL,
PERIOD_H1,
MODE_HIGH,
aGreenBoxWindow_HOURs_WIDE,
aGreenBoxWindow_H1Offset_ENDs
)
),
aGreenBoxWindow_DATETIME_ENDs
- aGreenBoxWindow_Duration_SECs,
iLow( NULL,
PERIOD_H1,
iLowest( NULL,
PERIOD_H1,
MODE_LOW,
aGreenBoxWindow_HOURs_WIDE,
aGreenBoxWindow_H1Offset_ENDs
)
)
);
ObjectSet( anObjNAME, OBJPROP_COLOR, DarkGreen );
ObjectSet( anObjNAME, OBJPROP_BACK, True );
}
else { // found .UPD
ObjectMove( anObjNAME, 0,
aGreenBoxWindow_DATETIME_ENDs,
iHigh( NULL,
PERIOD_H1,
iHighest( NULL,
PERIOD_H1,
MODE_HIGH,
aGreenBoxWindow_HOURs_WIDE,
aGreenBoxWindow_H1Offset_ENDs
)
)
);
ObjectMove( anObjNAME, 1,
aGreenBoxWindow_DATETIME_ENDs
- aGreenBoxWindow_Duration_SECs,
iLow( NULL,
PERIOD_H1,
iLowest( NULL,
PERIOD_H1,
MODE_LOW,
aGreenBoxWindow_HOURs_WIDE,
aGreenBoxWindow_H1Offset_ENDs
)
)
);
ObjectSet( anObjNAME, OBJPROP_COLOR, DarkGreen );
ObjectSet( anObjNAME, OBJPROP_BACK, True );
}
}
}