规划
9 |, F% j1 o2 v+ O) a0 P' l许多人可能认为规划很容易,特别是,由于它事关转换柱线,即始终把 1-分钟柱线转换为票据(我们稍后会解释)。 然而,模拟比表面看要复杂得多。 主要问题在于我们尚未清晰地理解票据的实际行为,就去创建 1-分钟柱线。 我们只有柱线,和一些它的有关信息,但我们并不知道柱线是如何形成的。 我们将采用 1-分钟柱线,因为它们所需的难度最小。 如果您能创造一个与真实事物非常相似的复杂走位,那么您就能够再现一些非常接近真实事物的东西。9 {% D! [7 r' x% R+ b
这个细节似乎并不那么重要,因为我们通常会在市场上看到锯齿形的走位。 无论走位如何复杂,这一切都归结为在 OHCL 点之间创建锯齿形。 它始自柱线的开盘那一刻,且需不少于 9 个走位来创造这个内部的锯齿形。 它总是在柱线收盘时结束,并在下一根柱线上重复该过程。 MetaTrader 5 策略测试器采用相同的逻辑。 更多详细信息,请参阅真实与生成的基差:算法交易。 我们将从这个策略开始。 虽然对于我们的目的来说并不理想,但它将为开拓更多适合的方式提供一个起点。
, m" E0 I( i+ V0 w就我而言,测试策略器不太适合回放/模拟系统,因为在策略测试器中,时间问题并不是最重要的。 这就是,没必要以这种方式创建和复现 1-分钟柱线,因为其长度本来就是 1-分钟。 事实上,它甚至更简略,在于它与现实时间并不对应。 如果是这样的话,那么测试策略就变得不可能。 想象一下,依据跨越几天甚至几年的柱运行测试,如果每根柱线复现时间与实际不同。 这将是一项不可能完成的任务。 然而,对于回放/模拟系统,我们正在寻找一种不同的行动。 我们希望按照 1-分钟间隔创建一根 1-分钟柱线,尽可能接近这个目标。% o& ] B L" ^
准备奠基. ]5 p( E" h \
我们的重点将完全放在回放/模拟服务代码上。 此时无需担心其它方面。 故此,我们将开始修改 C_Replay 类的代码,尝试尽可能地优化我们已经开发完成并测试过的东西。 下面是类中出现的第一个过程:
% f, P% U3 ?' S0 H4 O& Rinline bool CheckFileIsBar(int &file, const string szFileName)$ n" l; T, X0 k2 P2 f1 ?
{3 A1 O5 }3 R; I0 U- Z! m5 _
string szInfo = "";2 E/ v( a, F1 N! O
bool bRet;
) h {( R. [( F/ d4 r! }for (int c0 = 0; (c0 < 9) && (!FileIsEnding(file)); c0++) szInfo += FileReadString(file);
1 i7 f+ b2 x9 @8 G+ a- bif ((bRet = (szInfo == def_Header_Bar)) == false)
6 b9 W% [0 q8 ~: h{# p7 r, H8 e6 W$ `. v" ^
Print("File ", szFileName, ".csv is not a file with bars.");( P& @: ^5 }" I5 J" R& W* j" X9 r
FileClose(file);& d/ b; i* V. j6 ^
}& f0 D) P! k0 b; W& J; \: R
return bRet;7 A( ?( I! B! U6 G) V G
}3 q% ~& n3 d& a$ c l, h) P X: l
此处的目标是柱线读取函数,这些测试是为了判定指定文件是否为预览柱线文件。 这是必要的,当使用相同代码来判定柱线文件是否符合我们所需时,如此可避免重复代码。 在此状况下,这些柱线将不会用作预览柱线。 它们将被转换为模拟票据,以便在交易系统中使用。 有基于此,我们引入了另一个函数:
, C0 A( n+ ^: e% binline void FileReadBars(int &file, MqlRates &rate[])) D6 j4 @0 Z Z9 E7 i
{) K( a O0 [1 l3 t
rate[0].time = StringToTime(FileReadString(file) + " " + FileReadString(file));
) x) I; \2 M! _- h# Srate[0].open = StringToDouble(FileReadString(file));
7 V0 `8 W$ a- s3 m1 Urate[0].high = StringToDouble(FileReadString(file));
0 W" `. m& c% V1 C% S3 E& d' Qrate[0].low = StringToDouble(FileReadString(file));
/ q/ a2 i# R" b9 crate[0].close = StringToDouble(FileReadString(file));
$ p8 g. p7 e8 b, H) s+ rrate[0].tick_volume = StringToInteger(FileReadString(file));- F% j0 }, p: _+ ?" S
rate[0].real_volume = StringToInteger(FileReadString(file));
( o# u* b9 |$ |$ E/ Y# |, Jrate[0].spread = (int) StringToInteger(FileReadString(file));4 [" g' q6 n9 I
}
2 z$ Q# F; |; x它将从指定文件里逐行读取已有柱线的数据。 我想您在理解这段代码时不会遇到任何困难。 继续这个准备阶段,此处是另一个函数:: l3 I- \* K/ L0 { x* ^
inline bool OpenFileBars(int &file, const string szFileName)
: {; f/ n* b5 B5 J9 M; _; U{
0 a5 t* e" C+ G2 d6 ~' t# z. ?# Vif ((file = FileOpen("Market Replay\\Bars\\" + szFileName + ".csv", FILE_CSV | FILE_READ | FILE_ANSI)) != INVALID_HANDLE)/ B5 v3 G* G- K2 [/ |1 C9 h
{ N0 P+ x8 ?0 E
if (!CheckFileIsBar(file, szFileName))
3 O+ G6 R1 j; E' }" ^& Preturn false;1 `# v H: i' x% g5 Q( Y2 S; J
return true;1 \0 l I. `/ I
}
+ }' }4 c! ^& t4 o; C: i [9 xPrint("Falha ao acessar ", szFileName, ".csv de barras.");, g( {; B4 j3 Y' Q9 P0 W+ M
return false;1 s0 ]' ~0 _/ }8 ^+ X n8 p
}
; J1 o: O: Q) w我们的系统现在已经完全集中化,能提供对柱线的标准访问:我们即可把它们用作预览柱线时,亦可把它们用于模拟,并转换为票据表示。 因此,之前加载预览柱线的函数也必须修改,如下所示:5 ~6 H2 i: P( u3 O: g
bool LoadPrevBars(const string szFileNameCSV)4 y& ?, Z8 g2 I" d' Z0 A% H
{" }) R" @+ k1 C
int file,
6 ^2 c4 u0 Z/ s w2 u& aiAdjust = 0;
% u" \3 {; }3 a; h3 @# k" Qdatetime dt = 0;9 {5 N& }. O( ~# [/ k) |1 t
MqlRates Rate[1];- B" J- C+ M) c% f) S9 j% {
if (OpenFileBars(file, szFileNameCSV))
4 D$ l4 m3 @* a1 l/ Z{: E: i$ O8 L& d1 ~0 a, {- q# h {
Print("Loading preview bars for Replay. Please wait....");
4 ?$ {& ~9 K1 d- r# H) t/ Bwhile ((!FileIsEnding(file)) && (!_StopFlag))2 }$ l% q& a! X
{
' X, {3 E+ q4 n" u. W/ L JFileReadBars(file, Rate);
# x) t( q* T9 QiAdjust = ((dt != 0) && (iAdjust == 0) ? (int)(Rate[0].time - dt) : iAdjust);
/ d# |- M$ g( P/ a, [dt = (dt == 0 ? Rate[0].time : dt);
- `( ^' V7 A. u6 Z" yCustomRatesUpdate(def_SymbolReplay, Rate, 1); v* x# D6 m% p& s- w
}/ L& Z, O, t8 g2 h
m_dtPrevLoading = Rate[0].time + iAdjust;7 `5 r! H! l! q2 T! H3 r
FileClose(file);
d& A% w! v8 ^' |( t2 hreturn (!_StopFlag);1 M; [% s8 x/ {1 F9 m
}
. D2 @7 l$ z0 O/ M1 Cm_dtPrevLoading = 0;8 x5 V/ h- L8 R% E
return false;
7 ]' q& T& I) J0 z7 }% X5 J& X}; Q9 G/ q5 J/ s- ?6 g a
这个下载函数的工作方式并无变化,尽管现在有更多的调用。 从以前的函数中提取一部分,并在新位置加以运用,为我们提供了更高的安全性,因为所有代码都已经过测试。 以这种方式,我们只需要担心新函数。 现在地基已经准备就绪,我们需要在配置文件中添加新内容呢。 该函数旨在判定哪些柱线文件可用于模拟票据。 为此,我们需要添加一个新定义:
- \' C" n4 Y/ i% w#define def_STR_FilesBar "[BARS]"+ z5 X0 u9 K0 E1 @# ^. G! G4 `
#define def_STR_FilesTicks "[TICKS]"1 S0 z7 u# L9 t$ S
#define def_STR_TicksToBars "[TICKS->BARS]". } j. b2 p/ |: S Z/ @4 T
#define def_STR_BarsToTicks "[BARS->TICKS]"
. o6 `4 L" N( y这样我们就可以运行一个简单的测试,这正是我们开始进行模拟所需要的。 |