PSS C++ Backtesting Trading
Framework
(Professional
Software Solutions)
Jan 14, 2013
Currently integrated into BTSeqMgr - in stdafx.h"
//For BTSeqMgr undefine all below AND BARMGR_NORAREAVG
#define SEQ_HW 1 // Switch BTSeqMgr to Strategy external Testing Mode
#define BGM_BT 1 // Activate BT Functions in BGM/BCM Modules
Central new BTDlg Bar Processing hook:
int CBTSession::RunScript(const char *pFn,CTxt &txtErr)
int CBTSession::RunBTCmd(const char *pCmd,CTxt &txtErr)
int CPTStrat::Session_ProcessBar(CBTStratParMgr *pParMgr,BOOL bNewRun,CTxt &txtErr,CBarCalcData
*pNewTick)
Backtest Strat New TradeStation 9.5 is the new Optimization API PDF Video1 |
|||||||||
Backtest Strat a) Create new *.hws file in M:\srcpss\Apps\StockData\TS\BTSeqMgr b) Adjust StratName=XXX and Date Range etc c) Clone pars from *.sdef file d) Add new Strategy C++ class module hook in BTSeqMgrDlg.cpp: if (StringCompare(pDlg->m_BTS.GetStratName(),"MSC4",1) == 0) { CMSC4Strat *pMSC4 = new CMSC4Strat; pDlg->m_BTS.SetTopStrat(pMSC4); pMSC4->SetBTSes(&pDlg->m_BTS); } e) Add new Strategy C++ include to stdafx.h: #include "..\MyIdeas\BSP\BSPStrat.h" f) Remove all diagnostic Strat Messages LOGTARCE f) Adjust Commision ($8)and Duraction etc g) BTWFMgr output is the usual: C:\BTWFMgr\{Strat}\{Sym} h) Watch for MinMove setting to be 0.25 for ES futures! SymES= 1/MinMove|0.2500 2/BigPointAmt|50.00 3/Comm|8.0000 |
|||||||||
Check Entry Price a) As a new bar is added to the Setup - it checks if entry is hit: CTrdSetup::AddSetupBar() if (m_nStage == BCM_SET_ENTRYSTAGE) if (nBarTickH > nBarTickW) SetEntry(m_fPrcEWant); // Limit Order at price - cross needed b) Called from: CPTStrat::OnProcessSetups() pSetup->AddSetupBar() |
|||||||||
MSCChart: Dump Strategy Details: "SExp" in Command box Load Duration: in wdef: DataSrc=@ES|Mom2|10/26/2012|5 Days|C:\Database\MSC_TRD\ES_Mom0001_20121027.udd Strat=BSP1 |
|||||||||
Strat - Add new parameter: a) Add new members in CustStrat: float m_fParNew1; int m_nParNew2; .. b) Add init of parameters: |
|||||||||
Strat - Add new ENTRY attempt: pSetup->InitEntry(txtData,fPrcE,fStop,fTar,nSize); Change to: BCM_SET_ENTRYSTAGE m_nBarNbre set to current bar(1464) |
|||||||||
Strat - check if entry worked:
int CTrdSetup::AddSetupBar(CBarCalcData *pBar,float *pValOut) m_pStrat->m_bEntryLimitExact == TRUE m_pStrat->m_bEntryShouldCross == TRUE nBarTickL < nBarTickW(ant) if YES - call: int CTrdSetup::SetEntry(float fPrcE) with ACTUAL Entry Price set m_fPrcEGot, m_nBarNbrE, m_nDTE SetStage(BCM_SET_ENTRYSTAGE+1,txtData); case BCM_SET_ENTRYSTAGE: // still trying to enter nEntryWait = 1: first bar to try to enter |
|||||||||
Strat - when in Position: case BCM_SET_ENTRYSTAGE+1: int nAgePosBar = pSetup->GetPosAgeBar(); 0=first bar in Position int CTrdSetup::AddSetupBar(CBarCalcData *pBar,float *pValOut) int CTrdSetup::CheckExit(float *pValOut) pExit->CheckExit(&pBarLast->m_Bar,txtData,pValOut); |
|||||||||
Strat - Diagnostics in Setup Log: a) Default is: m_nBGMMode = BGM_MODE_FAST; (for fastest Backtesting!) b) Change via DEF file: 6/Diag|1 int CBTSession::RunBTCmd(const char *pCmd,CTxt &txtErr) CBTStratPar *pPar = m_StratPar.FindParByIdx(BCM_DIAG_COLIDX = 6); nBGMMode = (int)pPar->GetVal(0); Passed on for Indicator PlugIn in RunBTCmd(): m_pBGM->m_nBGMMode = (CBarCalcGlobalMgr::CBGMMode)nBGMMode; nBGMMode = (int)pPar->GetVal(0); m_pBGM->m_nBGMMode = (CBarCalcGlobalMgr::CBGMMode)nBGMMode; m_pStrat->SetDiag(m_pBGM->m_nBGMMode == CBarCalcGlobalMgr::BGM_MODE_DIAG); if (m_bRunAsIndicator == FALSE) m_pBGM->m_nBGMMode = CBarCalcGlobalMgr::BGM_MODE_FAST; |
|||||||||
Strat - Verbose level - AddMsg(): a) Verbose levels > 0 is needed for AddMsg() to add diag messages to the strategy diagnostic stream! b) When you create the Global CBarCalcGlobalMgr (m_BGM) then in DEBUG mode set the level to 1 or 2: #ifdef _DEBUG m_BGM.m_nBGMMode = CBarCalcGlobalMgr::BGM_MODE_DIAG; m_BGM.m_nVerbose = 2; #endif c) The top BGM Verbose Level is then passed on when the Strategy Indicator is cloned: CBarCalcTrack::InitStrat(CPTStrat *pStrat,const char *pDefName,CTxt &txtErr) m_pBGMTrack->m_nVerbose = m_pBCM->GetBGM()->m_nVerbose; //pass in the Verbose level from Parent BGM d) Can also be set via Config: CBarCalcGlobalMgr::CBarCalcGlobalMgr() m_nVerbose = GetIniLong("PSSTRD","VerboseLevel",0); |
|||||||||
Strat store Values in each Setup: a) Each setup can save its own values via: pSetLast->SetVal(fPivBSP,STRAT_BSP1); using: SFltArray m_arrSetupVal b) Declare Values in Strat.h (starting with seq 0): #undef STRAT_E_BAR #define STRAT_E_BAR 0 // Entry BarNbr #define STRAT_TAR_PRC 1 // Traget Price #define STRAT_STOP_PRC 2 // Traget Price #define STRAT_SETUP_BAR 3 // Setup Bar #define STRAT_PRC_WANT 4 // Wanted Entry #define STRAT_BSPCURR 5 // Current BSP Value #define STRAT_BSP1VAL 6 // BSP1 Value c) Define matching Column Header Text in constructor (EBar=0): CBSPStrat::CBSPStrat () { m_txtColHdr = "EBar|TarPrc|StopPrc|SBar|PrcWant|BSP1|BSP2|BSP3|"; |
|||||||||
Strat store Values across Setups (Bar related): a) Declare in Strat Object: class CBSPStrat : public CPTStrat { float m_fBSPNow; b) Populate from BarCalc etc in: CBSPStrat::CalcNewBar() //====== GET CALCULATED VALUES ===================== m_fBSPNow = GetBarLast1()->GetBarVal(BAR_BSP_SMOOTH); c) Transfer if needed to each Setup in: CBSPStrat::OnCalcSetup(CTrdSetup *pSetup,float *pValOut) //====== IMPRINT CALC VALUE(S) IN INDIVIDUAL SETUP ================= pSetup->SetVal(m_fBSPNow,STRAT_BSPCURR); |
|||||||||
Strat Indicator hook: a) Add Track: pTrack = pBCM->AddCalcTrack(CBarCalcTrack::BARCALC_TYP_STRAT1,nSrc,fPar,txtErr); b) Imprint new Strat: CPTStrat *pStrat = new CBSPStrat; if (pTrack->InitStrat(pStrat,"BSP1",txtErr) < 0) c) Strat is calculated in regular processing: int CBarCalcMgr::CalcNewBars(CTxt &txtErr) pTrack->CalcTrackBar(pBar); in BCM: case BARCALC_TYP_STRAT1: if (m_pBTS->AddIndicatorBar(pBar,txtErr) < 0) int CBTSession::AddIndicatorBar(CBarCalcData *pBar1,CTxt txtErr) |
|||||||||
Strat Result CSV Export: At the end of prcoessing call the CSV export function m_pBCMMain->StratIndExportCSV(txtErr); which will write Bar Data to: {HOME}/Bars_{Sym}_{Interval}.txt and Strategy Data to: {HOME}/Setup_{Sym}_{Interval}.txt |
|||||||||
Strat Indicator Parameter Load: After the Indicator Track has been added you have to initialize ONCE the startegy for the subsequent calc run: pTrack = pBCM->AddCalcTrack(CBarCalcTrack::BARCALC_TYP_STRAT1,nSrc,fPar,txtErr); //====== ATTACH STRAT TO IND ================================================ CPTStrat *pStrat = new CBSPStrat; if (pTrack->InitStrat(pStrat,"DefName",txtErr) < 0) return -3; Calling: int ret = m_pBTS->PrepareForIndicatorRun(txtFn,txtErr); DefName is the name of the strategy parameter definition file with only ONE permutation (in backtesting we have MANY permutations!) Example BSP1 -> {HOME}/BSP1.sdef |
|||||||||
Backtest Franmework: CBTSeqMgrDlg::ThreadBTRun
|
|||||||||
PTStrat Interface Functions: CPTStrat::Session_ProcessBar(CBTStratParMgr *pParMgr,BOOL bNewRun,CTxt &txtErr,CBarCalcData *pNewTick) Processes new Bar against the startegy logic pParMgr = Strategy Parameters bNewRun = One time TRUE when a new data run starts pNewTick= New Bar float m_fStratPar[BCM_MAXSTRATPAR]; // mirror of Strategy parameter bNewRun == TRUE a) Initialize the local strategy parameterr in m_fStratPar[] b) Initialize the BCM parameter (fMinMove, fAmtPerPt, fComm, nBGMMode, fStockPosAmt, bDiag) c) Call CXXXStrat ::OnStratSetInputs() - to allow custom strategy logic to initialize its internal parameters CXXXStrat ::OnCalcTracks(int nDataTrack,CBarCalcData *pBar,BOOL bAdd) a) Check if first time: GetNumStratTrack() < 1) - if yes - add calc tracks: GetBCM1()->AddCalcTrack() b) Run calculations for each calc track: pTrack->CalcTrackBar(pBar); Saves the track values into the Cal Bar: pBar->SetColFltVal(iColBar,fVal[iCol]); c) Real Strat processing: int ret = m_pBCM1->GetIBCMStrat()->OnProcessNewBar(NULL); CXXXStrat ::OnProcessNewBar(float *pValOut) a) CalcNewBar() - establish new bar: m_pBarLast1, m_nStratBarNbr1 set local calc values: fVal = GetBarLast1()->GetBarVal(BAR_XXX); b) OnCheckForNewSetup() - check if we found a new Startegy Setup trigger: CTrdSetup *pSetLast = GetLastSetup(); if setup: pSetLast = AddSetup( 1,GetBarLast1(),txtData,m_txtColHdr); in CPTStrat::AddSetup(int nDir,CBarCalcData *pBar1,const char *pMsg,const char *pHdr) c) CPTStrat::OnProcessSetups(float *pValOut) - processes EACH setup: pSetup->AddTickSetupBar(pBarNewTick,pValOut); CXXXStrat ::OnCalcSetup(CTrdSetup *pSetup,float *pValOut) c1) Custom logic to transition strategy stages: //====== CHECK STRATEGY STAGE ================================ switch (nStage) { case 1: break; case 2: break; case BCM_SET_ENTRYSTAGE: // still trying to enter can call: pSetup->ExitSetup(GetBarLast1(),NULL,pValOut); break; case BCM_SET_ENTRYSTAGE+1: can call: pSetup->ForceExit(txtData); break; } pSetup->SaveBarVal(pValOut); m_nStage = 1 - initial value - set in InitSetup BCM_SET_ENTRYSTAGE=10 // when we try to enter=10, 11=actually entered BCM_SET_DONESTAGE 20 // Setup has completed BCM_SET_KILLSTAGE 30 // Setup has killed itself m_bTickByTick == FALSE New Bars are all newly closed bars m_bTickByTick == TRUE New Bars are new ticks WITHIN a newly forming bar - accumulates the new bar values using m_BarNewTick m_bIntraBarTick |