00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <qlayout.h>
00023 #include <qvgroupbox.h>
00024 #include <qfile.h>
00025 #include <qtextstream.h>
00026 #include <qmessagebox.h>
00027 #include <qinputdialog.h>
00028 #include <qdir.h>
00029 #include <qprogressdialog.h>
00030 #include <qfileinfo.h>
00031 #include "Tester.h"
00032 #include "DbPlugin.h"
00033 #include "IndicatorPlugin.h"
00034 #include "HelpWindow.h"
00035 #include "DBIndexItem.h"
00036
00037
00038 Tester::Tester (QString n, DBIndex *i) : QTabDialog (0, 0, FALSE)
00039 {
00040 index = i;
00041 ruleName = n;
00042 recordList = 0;
00043 enterLongSignal.setAutoDelete(TRUE);
00044 exitLongSignal.setAutoDelete(TRUE);
00045 enterShortSignal.setAutoDelete(TRUE);
00046 exitShortSignal.setAutoDelete(TRUE);
00047 trades.setAutoDelete(TRUE);
00048
00049 QString s = "Qtstalker Back Tester";
00050 s.append(": ");
00051 s.append(ruleName);
00052 setCaption (s);
00053
00054 setDefaultButton(tr("&Test"));
00055 connect(this, SIGNAL(defaultButtonPressed()), this, SLOT(test()));
00056
00057 setApplyButton(tr("&Apply"));
00058 connect(this, SIGNAL(applyButtonPressed()), this, SLOT(saveRule()));
00059
00060 setCancelButton(tr("&Cancel"));
00061
00062 setOkButton(QString::null);
00063
00064 setHelpButton();
00065 QObject::connect(this, SIGNAL(helpButtonPressed()), this, SLOT(slotHelp()));
00066
00067 rulePage = new TesterRulePage(this);
00068 addTab(rulePage, tr("Rules"));
00069
00070 stopPage = new TesterStopPage(this);
00071 addTab(stopPage, tr("Stops"));
00072
00073 testPage = new TesterTestPage(this);
00074 addTab(testPage, tr("Testing"));
00075
00076 reportPage = new TesterReport(this);
00077 addTab(reportPage, tr("Reports"));
00078
00079 chartPage = new TesterChartPage(this, index);
00080 addTab(chartPage, tr("Chart"));
00081
00082 loadRule();
00083 }
00084
00085 Tester::Tester () : QTabDialog (0, 0, FALSE)
00086 {
00087 recordList = 0;
00088 }
00089
00090 Tester::~Tester ()
00091 {
00092 if (recordList)
00093 delete recordList;
00094 }
00095
00096 void Tester::saveRule ()
00097 {
00098 rulePage->saveEditRule(TesterRulePage::EnterLong, ruleName);
00099 rulePage->saveEditRule(TesterRulePage::ExitLong, ruleName);
00100 rulePage->saveEditRule(TesterRulePage::EnterShort, ruleName);
00101 rulePage->saveEditRule(TesterRulePage::ExitShort, ruleName);
00102
00103 stopPage->saveCustomStopRule(ruleName);
00104
00105 QString s;
00106 config.getData(Config::TestPath, s);
00107 s.append("/" + ruleName + "/rule");
00108 QFile f(s);
00109 if (! f.open(IO_WriteOnly))
00110 return;
00111 QTextStream stream(&f);
00112
00113 QStringList l;
00114 reportPage->getSummary(l);
00115 int loop;
00116 for (loop = 0; loop < (int) l.count(); loop++)
00117 stream << "Trade=" << l[loop] << "\n";
00118
00119 stream << "Maximum Loss Check=" << QString::number(stopPage->getMaximumLossCheck()) << "\n";
00120 stream << "Maximum Loss Long=" << QString::number(stopPage->getMaximumLossLong()) << "\n";
00121 stream << "Maximum Loss Short=" << QString::number(stopPage->getMaximumLossShort()) << "\n";
00122 stream << "Maximum Loss Edit=" << stopPage->getMaximumLossEdit() << "\n";
00123 stream << "Profit Check=" << QString::number(stopPage->getProfitCheck()) << "\n";
00124 stream << "Profit Long=" << QString::number(stopPage->getProfitLong()) << "\n";
00125 stream << "Profit Short=" << QString::number(stopPage->getProfitShort()) << "\n";
00126 stream << "Profit Edit=" << stopPage->getProfitEdit() << "\n";
00127 stream << "Trailing Check=" << QString::number(stopPage->getTrailingCheck()) << "\n";
00128 stream << "Trailing Long=" << QString::number(stopPage->getTrailingLong()) << "\n";
00129 stream << "Trailing Short=" << QString::number(stopPage->getTrailingShort()) << "\n";
00130 stream << "Trailing Edit=" << stopPage->getTrailingEdit() << "\n";
00131 stream << "TradeLong=" << QString::number(testPage->getTradeLong()) << "\n";
00132 stream << "TradeShort=" << QString::number(testPage->getTradeShort()) << "\n";
00133 stream << "Volume Percent=" << QString::number(testPage->getVolumePercent()) << "\n";
00134 stream << "Entry Com=" << QString::number(testPage->getEntryCom()) << "\n";
00135 stream << "Exit Com=" << QString::number(testPage->getExitCom()) << "\n";
00136 stream << "TradeDelay=" << QString::number(testPage->getTradeDelay()) << "\n";
00137 stream << "Price Field=" << testPage->getPriceField() << "\n";
00138 stream << "Bars=" << QString::number(testPage->getBars()) << "\n";
00139 stream << "Symbol=" << testPage->getSymbolPath() << "\n";
00140 stream << "Account=" << QString::number(testPage->getAccount()) << "\n";
00141 stream << "Compression=" << testPage->getBarLength() << "\n";
00142 stream << "CommissionType=" << QString::number(testPage->getCommissionType()) << "\n";
00143 stream << "FuturesMargin=" << QString::number(testPage->getMargin()) << "\n";
00144
00145 f.close();
00146 }
00147
00148 void Tester::loadRule ()
00149 {
00150 reportPage->clear();
00151
00152 rulePage->loadEditRule(TesterRulePage::EnterLong, ruleName);
00153 rulePage->loadEditRule(TesterRulePage::ExitLong, ruleName);
00154 rulePage->loadEditRule(TesterRulePage::EnterShort, ruleName);
00155 rulePage->loadEditRule(TesterRulePage::ExitShort, ruleName);
00156
00157 stopPage->loadCustomStopRule(ruleName);
00158
00159 QString s;
00160 config.getData(Config::TestPath, s);
00161 s.append("/" + ruleName + "/rule");
00162 QFile f(s);
00163 if (! f.open(IO_ReadOnly))
00164 return;
00165 QTextStream stream(&f);
00166
00167 while(stream.atEnd() == 0)
00168 {
00169 s = stream.readLine();
00170 s = s.stripWhiteSpace();
00171
00172 if (! s.length())
00173 continue;
00174
00175 QStringList l2 = QStringList::split("=", s, FALSE);
00176
00177 if (! l2[0].compare("Maximum Loss Check"))
00178 {
00179 stopPage->setMaximumLossCheck(l2[1].toInt());
00180 continue;
00181 }
00182
00183 if (! l2[0].compare("Maximum Loss Long"))
00184 {
00185 stopPage->setMaximumLossLong(l2[1].toInt());
00186 continue;
00187 }
00188
00189 if (! l2[0].compare("Maximum Loss Short"))
00190 {
00191 stopPage->setMaximumLossShort(l2[1].toInt());
00192 continue;
00193 }
00194
00195 if (! l2[0].compare("Maximum Loss Edit"))
00196 {
00197 stopPage->setMaximumLossEdit(l2[1]);
00198 continue;
00199 }
00200
00201 if (! l2[0].compare("Profit Check"))
00202 {
00203 stopPage->setProfitCheck(l2[1].toInt());
00204 continue;
00205 }
00206
00207 if (! l2[0].compare("Profit Long"))
00208 {
00209 stopPage->setProfitLong(l2[1].toInt());
00210 continue;
00211 }
00212
00213 if (! l2[0].compare("Profit Short"))
00214 {
00215 stopPage->setProfitShort(l2[1].toInt());
00216 continue;
00217 }
00218
00219 if (! l2[0].compare("Profit Edit"))
00220 {
00221 stopPage->setProfitEdit(l2[1]);
00222 continue;
00223 }
00224
00225 if (! l2[0].compare("Trailing Check"))
00226 {
00227 stopPage->setTrailingCheck(l2[1].toInt());
00228 continue;
00229 }
00230
00231 if (! l2[0].compare("Trailing Long"))
00232 {
00233 stopPage->setTrailingLong(l2[1].toInt());
00234 continue;
00235 }
00236
00237 if (! l2[0].compare("Trailing Short"))
00238 {
00239 stopPage->setTrailingShort(l2[1].toInt());
00240 continue;
00241 }
00242
00243 if (! l2[0].compare("Trailing Edit"))
00244 {
00245 stopPage->setTrailingEdit(l2[1]);
00246 continue;
00247 }
00248
00249 if (! l2[0].compare("TradeLong"))
00250 {
00251 testPage->setTradeLong(l2[1].toInt());
00252 continue;
00253 }
00254
00255 if (! l2[0].compare("TradeShort"))
00256 {
00257 testPage->setTradeShort(l2[1].toInt());
00258 continue;
00259 }
00260
00261 if (! l2[0].compare("Volume Percent"))
00262 {
00263 testPage->setVolumePercent(l2[1].toInt());
00264 continue;
00265 }
00266
00267 if (! l2[0].compare("Entry Com"))
00268 {
00269 testPage->setEntryCom(l2[1].toInt());
00270 continue;
00271 }
00272
00273 if (! l2[0].compare("Exit Com"))
00274 {
00275 testPage->setExitCom(l2[1].toInt());
00276 continue;
00277 }
00278
00279 if (! l2[0].compare("TradeDelay"))
00280 {
00281 testPage->setTradeDelay(l2[1].toInt());
00282 continue;
00283 }
00284
00285 if (! l2[0].compare("Bars"))
00286 {
00287 testPage->setBars(l2[1].toInt());
00288 continue;
00289 }
00290
00291 if (! l2[0].compare("Price Field"))
00292 {
00293 testPage->setPriceField(l2[1]);
00294 continue;
00295 }
00296
00297 if (! l2[0].compare("Symbol"))
00298 {
00299 testPage->setSymbol(l2[1]);
00300 continue;
00301 }
00302
00303 if (! l2[0].compare("Account"))
00304 {
00305 testPage->setAccount(l2[1].toInt());
00306 continue;
00307 }
00308
00309 if (! l2[0].compare("Trade"))
00310 {
00311 TradeItem *trade = new TradeItem;
00312 reportPage->addTrade(l2[1], trade);
00313 trades.append(trade);
00314 continue;
00315 }
00316
00317 if (! l2[0].compare("Compression"))
00318 {
00319 testPage->setBarLength(l2[1]);
00320 continue;
00321 }
00322
00323 if (! l2[0].compare("CommissionType"))
00324 {
00325 testPage->setCommissionType(l2[1].toInt());
00326 continue;
00327 }
00328
00329 if (! l2[0].compare("FuturesMargin"))
00330 testPage->setMargin(l2[1].toInt());
00331 }
00332 f.close();
00333
00334 s = testPage->getSymbolPath();
00335 DbPlugin db;
00336 if (db.open(s, index))
00337 {
00338 db.close();
00339 return;
00340 }
00341
00342 QFileInfo fi(s);
00343 QString fn = fi.fileName();
00344
00345 DBIndexItem item;
00346 index->getIndexItem(fn, item);
00347 item.getType(chartType);
00348 if (! chartType.compare(tr("Futures")))
00349 item.getFuturesType(futuresType);
00350
00351 db.close();
00352
00353 int loop;
00354 for (loop = 0; loop < (int) trades.count(); loop++)
00355 {
00356 TradeItem *trade = trades.at(loop);
00357 trade->setCommissionType(testPage->getCommissionType());
00358 trade->setEntryCom(testPage->getEntryCom());
00359 trade->setExitCom(testPage->getExitCom());
00360
00361 if (! chartType.compare(tr("Futures")))
00362 {
00363 trade->setStockFlag(FALSE);
00364 trade->setFuturesType(futuresType);
00365 }
00366
00367 if (! loop)
00368 trade->setBalance(testPage->getAccount());
00369 else
00370 {
00371 TradeItem *ttrade = trades.at(loop - 1);
00372 trade->setBalance(ttrade->getBalance());
00373 }
00374
00375 trade->calculateProfit();
00376 }
00377
00378 chartPage->clear();
00379
00380 reportPage->createSummary(trades, testPage->getAccount());
00381 }
00382
00383 void Tester::exitDialog ()
00384 {
00385 saveRule();
00386 accept();
00387 }
00388
00389 int Tester::getVolume (int i, double d)
00390 {
00391 double balance = d;
00392 int volume = 1;
00393 if (testPage->getVolumePercent() == 0)
00394 return volume;
00395
00396 balance = balance * ((double) testPage->getVolumePercent() / 100.0);
00397
00398 if (testPage->getMargin())
00399 volume = (int) (double) (balance / testPage->getMargin());
00400 else
00401 volume = (int) (double) (balance / getPrice(i));
00402
00403 return volume;
00404 }
00405
00406 double Tester::getPrice (int i)
00407 {
00408 double price = 0;
00409
00410 if (! testPage->getPriceField().compare(tr("Open")))
00411 price = recordList->getOpen(i);
00412 else
00413 {
00414 if (! testPage->getPriceField().compare(tr("Close")))
00415 price = recordList->getClose(i);
00416 else
00417 price = recordList->getLow(i) + ((recordList->getHigh(i) - recordList->getLow(i)) / 2);
00418 }
00419
00420 return price;
00421 }
00422
00423 QString Tester::newTest ()
00424 {
00425 bool ok;
00426 QString s = QInputDialog::getText(tr("New Backtest Rule"),
00427 tr("Enter new backtest rule name."),
00428 QLineEdit::Normal,
00429 tr("NewRule"),
00430 &ok,
00431 this);
00432
00433 if ((! ok) || (s.isNull()))
00434 return s;
00435
00436 int loop;
00437 QString selection;
00438 for (loop = 0; loop < (int) s.length(); loop++)
00439 {
00440 QChar c = s.at(loop);
00441 if (c.isLetterOrNumber())
00442 selection.append(c);
00443 }
00444
00445 config.getData(Config::TestPath, s);
00446 s.append("/" + selection);
00447 QDir dir(s);
00448 if (dir.exists(s, TRUE))
00449 {
00450 QMessageBox::information(this, tr("Qtstalker: Error"), tr("This backtest rule already exists."));
00451 return selection;
00452 }
00453
00454 if (! dir.mkdir(s, TRUE))
00455 {
00456 qDebug("TestPage::newTest:can't create dir %s", s.latin1());
00457 return selection;
00458 }
00459
00460 if (! dir.mkdir(s + "/el", TRUE))
00461 {
00462 qDebug("TestPage::newTest:can't create el dir");
00463 return selection;
00464 }
00465
00466 if (! dir.mkdir(s + "/xl", TRUE))
00467 {
00468 qDebug("TestPage::newTest:can't create xl dir");
00469 return selection;
00470 }
00471
00472 if (! dir.mkdir(s + "/es", TRUE))
00473 {
00474 qDebug("TestPage::newTest:can't create es dir");
00475 return selection;
00476 }
00477
00478 if (! dir.mkdir(s + "/xs", TRUE))
00479 {
00480 qDebug("TestPage::newTest:can't create xs dir");
00481 return selection;
00482 }
00483
00484 return selection;
00485 }
00486
00487 void Tester::slotHelp ()
00488 {
00489 HelpWindow *hw = 0;
00490 QString str;
00491 QString s = tabLabel(currentPage());
00492
00493 while (s.length())
00494 {
00495 if (! s.compare("Rules"))
00496 {
00497 str = "backtesterrules.html";
00498 hw = new HelpWindow(this, str);
00499 break;
00500 }
00501
00502 if (! s.compare("Stops"))
00503 {
00504 str = "backtesterstops.html";
00505 hw = new HelpWindow(this, str);
00506 break;
00507 }
00508
00509 if (! s.compare("Testing"))
00510 {
00511 str = "backtestertesting.html";
00512 hw = new HelpWindow(this, str);
00513 break;
00514 }
00515
00516 if (! s.compare("Reports"))
00517 {
00518 str = "backtesterreports.html";
00519 hw = new HelpWindow(this, str);
00520 break;
00521 }
00522
00523 if (! s.compare("Chart"))
00524 {
00525 str = "backtesterchart.html";
00526 hw = new HelpWindow(this, str);
00527 break;
00528 }
00529
00530 break;
00531 }
00532
00533 if (hw)
00534 hw->show();
00535 }
00536
00537 void Tester::loadSignals ()
00538 {
00539 enterLongSignal.clear();
00540 exitLongSignal.clear();
00541 enterShortSignal.clear();
00542 exitShortSignal.clear();
00543
00544
00545 QString plugin("CUS");
00546 IndicatorPlugin *plug = config.getIndicatorPlugin(plugin);
00547 if (! plug)
00548 {
00549 config.closePlugin(plugin);
00550 return;
00551 }
00552
00553 int loop;
00554 for (loop = 0; loop < 4; loop++)
00555 {
00556 QStringList l;
00557 switch (loop)
00558 {
00559 case 0:
00560 l = QStringList::split("\n", rulePage->getEditRule(TesterRulePage::EnterLong));
00561 break;
00562 case 1:
00563 l = QStringList::split("\n", rulePage->getEditRule(TesterRulePage::ExitLong));
00564 break;
00565 case 2:
00566 l = QStringList::split("\n", rulePage->getEditRule(TesterRulePage::EnterShort));
00567 break;
00568 case 3:
00569 l = QStringList::split("\n", rulePage->getEditRule(TesterRulePage::ExitShort));
00570 break;
00571 default:
00572 break;
00573 }
00574
00575 if (! l.count())
00576 continue;
00577
00578 plug->setCustomFunction(l);
00579
00580
00581 plug->setIndicatorInput(recordList);
00582 Indicator *i = plug->calculate();
00583 PlotLine *line = i->getLine(0);
00584 if (! line)
00585 {
00586 qDebug("Tester::loadSignals: no PlotLine returned");
00587 delete i;
00588 continue;
00589 }
00590
00591 int loop2 = recordList->count() - line->getSize();
00592 int lineLoop = 0;
00593 Setting *trade = 0;
00594 for (; loop2 < (int) recordList->count(); loop2++, lineLoop++)
00595 {
00596 if (line->getData(lineLoop) == 1)
00597 {
00598 if (! trade)
00599 {
00600 trade = new Setting;
00601 QDateTime dt;
00602 recordList->getDate(loop2, dt);
00603 QString key = dt.toString("yyyyMMddhhmmss");
00604 switch (loop)
00605 {
00606 case 0:
00607 enterLongSignal.replace(key, trade);
00608 break;
00609 case 1:
00610 exitLongSignal.replace(key, trade);
00611 break;
00612 case 2:
00613 enterShortSignal.replace(key, trade);
00614 break;
00615 case 3:
00616 exitShortSignal.replace(key, trade);
00617 break;
00618 default:
00619 break;
00620 }
00621 }
00622 }
00623 else
00624 {
00625 if (trade)
00626 trade = 0;
00627 }
00628 }
00629
00630 delete i;
00631 }
00632
00633 config.closePlugin(plugin);
00634 }
00635
00636 void Tester::test ()
00637 {
00638 if (! testPage->getTradeLong() && ! testPage->getTradeShort())
00639 return;
00640
00641 equity = (double) testPage->getAccount();
00642 if (equity == 0)
00643 return;
00644
00645 QString symbol = testPage->getSymbol();
00646 if (! symbol.length())
00647 return;
00648
00649 QString path = testPage->getSymbolPath();
00650 DbPlugin db;
00651 QDir dir;
00652 if (! dir.exists(path))
00653 return;
00654
00655 if (db.open(path, index))
00656 {
00657 db.close();
00658 return;
00659 }
00660
00661 QFileInfo fi(path);
00662 QString fn = fi.fileName();
00663
00664 DBIndexItem item;
00665 index->getIndexItem(fn, item);
00666 item.getType(chartType);
00667 if (! chartType.compare(tr("Futures")))
00668 item.getFuturesType(futuresType);
00669
00670 db.setBarLength((BarData::BarLength) testPage->getBarLengthIndex());
00671 db.setBarRange(testPage->getBars());
00672 if (recordList)
00673 delete recordList;
00674 recordList = new BarData(path);
00675 QDateTime dt = QDateTime::currentDateTime();
00676 db.getHistory(recordList, dt);
00677 db.close();
00678
00679 chartPage->clear();
00680
00681 loadSignals();
00682
00683 if (stopPage->loadCustomLongStop(recordList))
00684 return;
00685
00686 if (stopPage->loadCustomShortStop(recordList))
00687 return;
00688
00689 reportPage->clear();
00690 trades.clear();
00691
00692 QProgressDialog prog(tr("Testing..."),
00693 tr("Cancel"),
00694 testPage->getBars(),
00695 this,
00696 "progress",
00697 TRUE);
00698 prog.show();
00699
00700 this->setEnabled(FALSE);
00701
00702 currentRecord = 0;
00703 for (; currentRecord < (int) recordList->count(); currentRecord++)
00704 {
00705 prog.setProgress(currentRecord);
00706 emit message(QString());
00707 if (prog.wasCancelled())
00708 break;
00709
00710 QDateTime dt;
00711 recordList->getDate(currentRecord, dt);
00712 QString key = dt.toString("yyyyMMddhhmmss");
00713
00714 if (testPage->getTradeLong())
00715 {
00716 Setting *set = enterLongSignal[key];
00717 if (set)
00718 enterTrade(TradeItem::Long);
00719 }
00720
00721 if (testPage->getTradeShort())
00722 {
00723 Setting *set = enterShortSignal[key];
00724 if (set)
00725 enterTrade(TradeItem::Short);
00726 }
00727 }
00728
00729 reportPage->createSummary(trades, testPage->getAccount());
00730
00731 chartPage->updateChart(recordList, trades, testPage->getAccount());
00732
00733 db.close();
00734
00735 this->setEnabled(TRUE);
00736 }
00737
00738 void Tester::enterTrade (TradeItem::TradePosition flag)
00739 {
00740 TradeItem *trade = new TradeItem;
00741 trade->setTradePosition(flag);
00742 if (flag == TradeItem::Long)
00743 trade->setEnterSignal(TradeItem::EnterLong);
00744 else
00745 trade->setEnterSignal(TradeItem::EnterShort);
00746
00747 int buyRecord = 0;
00748 if (currentRecord + testPage->getTradeDelay() < recordList->count())
00749 buyRecord = currentRecord + testPage->getTradeDelay();
00750 else
00751 buyRecord = currentRecord;
00752
00753 QDateTime td;
00754 recordList->getDate(buyRecord, td);
00755 trade->setEnterDate(td);
00756
00757 double enterPrice = getPrice(buyRecord);
00758 trade->setEnterPrice(enterPrice);
00759
00760 stopPage->setTrailingHigh(getPrice(buyRecord));
00761
00762 if (! trades.count())
00763 {
00764 trade->setVolume(getVolume(buyRecord, testPage->getAccount()));
00765 trade->setBalance(testPage->getAccount());
00766 }
00767 else
00768 {
00769 TradeItem *t = trades.at(trades.count() - 1);
00770 trade->setVolume(getVolume(buyRecord, t->getBalance()));
00771 trade->setBalance(t->getBalance());
00772 }
00773 if (trade->getVolume() == 0)
00774 {
00775 delete trade;
00776 return;
00777 }
00778
00779 trade->setCommissionType(testPage->getCommissionType());
00780
00781 trade->setEntryCom(testPage->getEntryCom());
00782
00783 trade->setExitCom(testPage->getExitCom());
00784
00785 if (! chartType.compare(tr("Futures")))
00786 {
00787 trade->setStockFlag(FALSE);
00788 trade->setFuturesType(futuresType);
00789 trade->setMargin(testPage->getMargin());
00790 }
00791
00792 int loop = buyRecord;
00793 for (; loop < (int) recordList->count(); loop++)
00794 {
00795 QDateTime dt;
00796 recordList->getDate(loop, dt);
00797 QString key = dt.toString("yyyyMMddhhmmss");
00798
00799 Setting *set = 0;
00800 if (flag == TradeItem::Long)
00801 set = exitLongSignal[key];
00802 else
00803 set = exitShortSignal[key];
00804 if (set)
00805 {
00806 int sellRecord = 0;
00807 if (loop + testPage->getTradeDelay() < recordList->count())
00808 sellRecord = loop + testPage->getTradeDelay();
00809 else
00810 sellRecord = loop;
00811
00812 recordList->getDate(sellRecord, td);
00813 trade->setExitDate(td);
00814 trade->setExitPrice(getPrice(sellRecord));
00815 if (flag == TradeItem::Long)
00816 trade->setExitSignal(TradeItem::ExitLong);
00817 else
00818 trade->setExitSignal(TradeItem::ExitShort);
00819 trades.append(trade);
00820 currentRecord = loop - 1;
00821 trade->calculateProfit();
00822 break;
00823 }
00824
00825 bool tflag = FALSE;
00826 if (flag == TradeItem::Long)
00827 tflag = stopPage->maximumLoss(FALSE, enterPrice, recordList->getLow(loop));
00828 else
00829 tflag = stopPage->maximumLoss(TRUE, enterPrice, recordList->getHigh(loop));
00830 if (tflag)
00831 {
00832 int sellRecord = 0;
00833 if (loop + testPage->getTradeDelay() < recordList->count())
00834 sellRecord = loop + testPage->getTradeDelay();
00835 else
00836 sellRecord = loop;
00837
00838 recordList->getDate(sellRecord, td);
00839 trade->setExitDate(td);
00840 trade->setExitPrice(getPrice(sellRecord));
00841 trade->setExitSignal(TradeItem::MaximumLoss);
00842 trades.append(trade);
00843 currentRecord = loop - 1;
00844 trade->calculateProfit();
00845 break;
00846 }
00847
00848 if (flag == TradeItem::Long)
00849 tflag = stopPage->profit(FALSE, enterPrice, recordList->getHigh(loop));
00850 else
00851 tflag = stopPage->profit(TRUE, enterPrice, recordList->getLow(loop));
00852 if (tflag)
00853 {
00854 int sellRecord = 0;
00855 if (loop + testPage->getTradeDelay() < recordList->count())
00856 sellRecord = loop + testPage->getTradeDelay();
00857 else
00858 sellRecord = loop;
00859
00860 recordList->getDate(sellRecord, td);
00861 trade->setExitDate(td);
00862 trade->setExitPrice(getPrice(sellRecord));
00863 trade->setExitSignal(TradeItem::Profit);
00864 trades.append(trade);
00865 currentRecord = loop - 1;
00866 trade->calculateProfit();
00867 break;
00868 }
00869
00870 if (flag == TradeItem::Long)
00871 tflag = stopPage->customStop(FALSE, loop);
00872 else
00873 tflag = stopPage->customStop(TRUE, loop);
00874 if (tflag)
00875 {
00876 int sellRecord = 0;
00877 if (loop + testPage->getTradeDelay() < recordList->count())
00878 sellRecord = loop + testPage->getTradeDelay();
00879 else
00880 sellRecord = loop;
00881
00882 recordList->getDate(sellRecord, td);
00883 trade->setExitDate(td);
00884 trade->setExitPrice(getPrice(sellRecord));
00885 trade->setExitSignal(TradeItem::CUSStop);
00886 trades.append(trade);
00887 currentRecord = loop - 1;
00888 trade->calculateProfit();
00889 break;
00890 }
00891
00892 if (flag == TradeItem::Long)
00893 tflag = stopPage->trailing(FALSE, recordList->getLow(loop));
00894 else
00895 tflag = stopPage->trailing(TRUE, recordList->getHigh(loop));
00896 if (tflag)
00897 {
00898 int sellRecord = 0;
00899 if (loop + testPage->getTradeDelay() < recordList->count())
00900 sellRecord = loop + testPage->getTradeDelay();
00901 else
00902 sellRecord = loop;
00903
00904 recordList->getDate(sellRecord, td);
00905 trade->setExitDate(td);
00906 trade->setExitPrice(getPrice(sellRecord));
00907 trade->setExitSignal(TradeItem::Trailing);
00908 trades.append(trade);
00909 currentRecord = loop - 1;
00910 trade->calculateProfit();
00911 break;
00912 }
00913 }
00914
00915 if (trade->getExitSignal() == TradeItem::None)
00916 {
00917 recordList->getDate(recordList->count() - 1, td);
00918 trade->setExitDate(td);
00919 trade->setExitPrice(getPrice(recordList->count() - 1));
00920 trade->setExitSignal(TradeItem::EndTest);
00921 trades.append(trade);
00922 currentRecord = loop;
00923 trade->calculateProfit();
00924 }
00925 }
00926