规划1 g5 R' z# `2 C
许多人可能认为规划很容易,特别是,由于它事关转换柱线,即始终把 1-分钟柱线转换为票据(我们稍后会解释)。 然而,模拟比表面看要复杂得多。 主要问题在于我们尚未清晰地理解票据的实际行为,就去创建 1-分钟柱线。 我们只有柱线,和一些它的有关信息,但我们并不知道柱线是如何形成的。 我们将采用 1-分钟柱线,因为它们所需的难度最小。 如果您能创造一个与真实事物非常相似的复杂走位,那么您就能够再现一些非常接近真实事物的东西。
7 _5 L: ?* g3 X2 E; e. W这个细节似乎并不那么重要,因为我们通常会在市场上看到锯齿形的走位。 无论走位如何复杂,这一切都归结为在 OHCL 点之间创建锯齿形。 它始自柱线的开盘那一刻,且需不少于 9 个走位来创造这个内部的锯齿形。 它总是在柱线收盘时结束,并在下一根柱线上重复该过程。 MetaTrader 5 策略测试器采用相同的逻辑。 更多详细信息,请参阅真实与生成的基差:算法交易。 我们将从这个策略开始。 虽然对于我们的目的来说并不理想,但它将为开拓更多适合的方式提供一个起点。 j G" {% P( ?6 J4 Q7 I
就我而言,测试策略器不太适合回放/模拟系统,因为在策略测试器中,时间问题并不是最重要的。 这就是,没必要以这种方式创建和复现 1-分钟柱线,因为其长度本来就是 1-分钟。 事实上,它甚至更简略,在于它与现实时间并不对应。 如果是这样的话,那么测试策略就变得不可能。 想象一下,依据跨越几天甚至几年的柱运行测试,如果每根柱线复现时间与实际不同。 这将是一项不可能完成的任务。 然而,对于回放/模拟系统,我们正在寻找一种不同的行动。 我们希望按照 1-分钟间隔创建一根 1-分钟柱线,尽可能接近这个目标。
7 T/ [1 C, p7 i5 A$ W' @ {准备奠基5 D X7 @8 n4 u6 ~
我们的重点将完全放在回放/模拟服务代码上。 此时无需担心其它方面。 故此,我们将开始修改 C_Replay 类的代码,尝试尽可能地优化我们已经开发完成并测试过的东西。 下面是类中出现的第一个过程:
8 l- L( b# {0 P. Rinline bool CheckFileIsBar(int &file, const string szFileName)/ X3 g6 `; c, y- F+ E
{0 t0 `7 r* v E0 `- z! o3 x
string szInfo = "";% P, q: o& l; o H1 I2 U# k
bool bRet;
1 [8 u7 Y' G X; h5 I* f- vfor (int c0 = 0; (c0 < 9) && (!FileIsEnding(file)); c0++) szInfo += FileReadString(file);
. \7 s- W/ N6 ?/ }9 F5 f; ~if ((bRet = (szInfo == def_Header_Bar)) == false)
6 E& v; _. m6 v* o# c4 W{
. J3 Q. v. X& Q/ s" X, CPrint("File ", szFileName, ".csv is not a file with bars.");+ A. ^, R6 i$ B; R6 @
FileClose(file);, ?3 e7 t4 i7 n% i6 r5 K, p0 R+ O7 b
}
6 o5 V1 m& ?* ~2 k4 a* [* k5 r: B$ [! Xreturn bRet;& ~7 P8 ~1 o. U, \7 ~8 f
}( Y: D0 g, l3 w! B$ @
此处的目标是柱线读取函数,这些测试是为了判定指定文件是否为预览柱线文件。 这是必要的,当使用相同代码来判定柱线文件是否符合我们所需时,如此可避免重复代码。 在此状况下,这些柱线将不会用作预览柱线。 它们将被转换为模拟票据,以便在交易系统中使用。 有基于此,我们引入了另一个函数:( M, M6 n1 _% Q5 A
inline void FileReadBars(int &file, MqlRates &rate[]) P/ y3 H- T5 A/ K% b- @
{+ s- F7 [- Y9 V: T- v( _
rate[0].time = StringToTime(FileReadString(file) + " " + FileReadString(file));
& A$ s- h& v4 urate[0].open = StringToDouble(FileReadString(file));
9 t5 {) x! h3 N1 `rate[0].high = StringToDouble(FileReadString(file));( V: }* U8 m+ G- l8 Z' G7 T
rate[0].low = StringToDouble(FileReadString(file));
& {/ ], Q& O" E5 _6 X2 |rate[0].close = StringToDouble(FileReadString(file));( |2 q' Q! L: z% d5 _$ u
rate[0].tick_volume = StringToInteger(FileReadString(file));
0 p( n# F6 _+ s2 e( \rate[0].real_volume = StringToInteger(FileReadString(file));+ c3 V% f! ]* q! b
rate[0].spread = (int) StringToInteger(FileReadString(file));
$ b& t# F) O, D+ \6 _}' h1 w' T6 I* L* _
它将从指定文件里逐行读取已有柱线的数据。 我想您在理解这段代码时不会遇到任何困难。 继续这个准备阶段,此处是另一个函数:
. H, ^# Q/ ?, d: `6 qinline bool OpenFileBars(int &file, const string szFileName). w) b8 L" i9 c0 G$ x
{
3 |( S7 w8 i" H1 T% a1 Gif ((file = FileOpen("Market Replay\\Bars\\" + szFileName + ".csv", FILE_CSV | FILE_READ | FILE_ANSI)) != INVALID_HANDLE)
' p: T$ L- n! W; W{0 u5 _5 _3 K9 ^
if (!CheckFileIsBar(file, szFileName))
6 w- ~: p4 R( t4 e4 L/ A! _* N' c. z' ~return false;. T4 C% t1 `3 e) ? B
return true;
8 Q6 L) u, [/ X& o- m8 @* B* M# r}
4 E# ]* g* ~9 V" a$ [, ?Print("Falha ao acessar ", szFileName, ".csv de barras.");& g; Y: T2 f, W8 D; }8 Z0 I5 P
return false;3 S1 ^, Q8 |6 {0 ]6 h
}
- ?- \0 n* D6 g* _+ K6 n2 @2 e" W. c我们的系统现在已经完全集中化,能提供对柱线的标准访问:我们即可把它们用作预览柱线时,亦可把它们用于模拟,并转换为票据表示。 因此,之前加载预览柱线的函数也必须修改,如下所示:
0 M8 t, W- x# z4 }7 Cbool LoadPrevBars(const string szFileNameCSV)
: k9 L' H$ V+ c3 I' t{
* h9 B6 p m! p/ P! Dint file,& B! c% t4 n* c
iAdjust = 0;
2 _- O) ]% A! z8 _! u2 edatetime dt = 0;# K6 U6 P) `5 H
MqlRates Rate[1];# K; ?: ^1 w- G' G) Q$ _- F
if (OpenFileBars(file, szFileNameCSV))
8 E8 ~( I3 S4 e2 d{+ `4 o: M; K! d0 P7 k; |2 b% b
Print("Loading preview bars for Replay. Please wait....");
4 b) I, ]3 ~% `/ P6 r2 [while ((!FileIsEnding(file)) && (!_StopFlag))
7 R- h$ ~: L) \$ n/ q{
" i3 h4 ?( ]1 Y, i* BFileReadBars(file, Rate);
5 q3 d4 n. r+ w& C8 c$ h- y) ]iAdjust = ((dt != 0) && (iAdjust == 0) ? (int)(Rate[0].time - dt) : iAdjust);5 i( a, c% ~+ j0 S n( _
dt = (dt == 0 ? Rate[0].time : dt);
. U0 c# J+ F' E8 h8 X; W; kCustomRatesUpdate(def_SymbolReplay, Rate, 1);- A1 k& w/ O" D/ g& m
}7 X1 O4 k' t8 A, Q- h+ `" @
m_dtPrevLoading = Rate[0].time + iAdjust;
7 k% x4 D+ p, s6 y1 [. sFileClose(file);# B) d u' M1 L) H; T
return (!_StopFlag);8 q) ~. C3 L; C9 i
}
2 F6 N! @8 q! g. om_dtPrevLoading = 0;# F, n" h7 {; u2 |
return false;5 p9 o5 T( G* q6 {( P h( Q
}
: y& b" Q1 w2 {" }这个下载函数的工作方式并无变化,尽管现在有更多的调用。 从以前的函数中提取一部分,并在新位置加以运用,为我们提供了更高的安全性,因为所有代码都已经过测试。 以这种方式,我们只需要担心新函数。 现在地基已经准备就绪,我们需要在配置文件中添加新内容呢。 该函数旨在判定哪些柱线文件可用于模拟票据。 为此,我们需要添加一个新定义:( a$ W8 E: t0 }/ s) o+ f
#define def_STR_FilesBar "[BARS]"# w! [( `: F- u, v* M! t
#define def_STR_FilesTicks "[TICKS]"
' U7 Z. q1 T, m6 g& R#define def_STR_TicksToBars "[TICKS->BARS]"5 U! U j$ P6 H1 V
#define def_STR_BarsToTicks "[BARS->TICKS]"
+ Y i8 F4 S; w/ }9 _这样我们就可以运行一个简单的测试,这正是我们开始进行模拟所需要的。 |