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
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: 
CBSPStrat::OnStratSetInputs()
 m_fParNew1 = GetStratParFlt(21);
 m_fParNew2 = GetStratParInt(22);

c) Add parameters in strategy text definition: 
21/ParNew1|10.8
22/ParNew2|20

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
Name Description
CBTStratParMgr In BTSeqssion - m_StratPar - Strategy Parameter Manager
CPTStrat::Session_ProcessBar Processes new Bar againstthe startegy logic
WaitStartOpt  
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