PureBytes Links
Trading Reference Links
|
Further thoughts on the code I posted:
* I realized that a bar-by-bar equity indicator is overkill for most
traders, and needlessly adds complexity and wastes global memory.
Most people who trade a basket of systems are not going to watch the
aggregate equity on a minute-by-minute basis. I suspect a daily
equity indicator would be sufficient for nearly everyone. So, change
the TimeIndex calculation (on both the "storing" code AND the
"reading" code in the indicator) to offset by days, not bars:
TimeIndex = NowDate - StartDate. That allocates memory for one
equity value per day, per system. Then only run the
storage/retrieval code on a daily basis. (See revised code, below.)
The value of SysEquity in the indicator will remain unchanged during
the trading day, so even if you're charting intraday data the
indicator will continue to plot the total start-of-day equity
throughout the day.
BTW, this change solves the problem of running systems with different
timeframes. As long as all your systems are daily or less, they can
all play together with this approach. Whether they run on 1min or
60min bars, they all store one equity value per day. If you run some
of your systems on weekly or monthly bars, you should add code to
fill in the daily values between your weekly/monthly bars so your
equity indicator can retrieve valid equity values for your weekly and
monthly systems, and plot valid equity on a daily basis. (Or you
could just plot the equity indicator on a weekly/monthly chart, and
ignore the daily equity changes from your other systems.)
* I should have made the code a bit more bombproof. In particular,
the code I posted won't behave very well if you run system 1 through
N, or the indicator, before running System 0 to initialize memory.
If System 0 hasn't written the StartDate value into memory, the other
code will try to compute a NowDate-StartDate offset using whatever
value is in the StartDate location. This is likely to result in a
bogus TimeIndex value that might access illegal memory locations.
So let's add a bit of protection. I've inserted a "marker" value in
global memory when I initialize StartDate, and I only allow the other
code to access StartDate if the "marker" is present. I also generate
the marker value *using* the value of StartDate, so that marker is
valid only for that StartDate. It's sort of like a "parity check"
for StartDate.
This prevents you from accessing a bogus value of StartDate before
System 0 has run the *first* time, AND if you change the value of
StartDate for System 0.
* I said that you might want to run the equity indicator on the same
chart as your master system. On further thought that's probably not
a good idea. To make sure your equity plot is valid, you shouldn't
run the equity indicator until ALL other systems have run and stored
their equity values. So you should probably run the equity indicator
on a separate chart, or at least on the same chart as the LAST system
that you run.
You might want to put System 0 in one workspace, and all other
systems and the indicator in another workspace. That allows you to
control the order that they get run. Open the System 0 workspace
first, THEN open the everything-else workspace.
* I added a plot line to show Maximum equity to date (closed or open,
depending on what you decided to store). This makes it easier to see
drawdowns.
Again, let me warn you that I haven't tested this code. I've spent
way too much time on it already. :-) But it should be very close to
what you need, and hopefully it was an instructive exercise for
everyone who stuck with me this far.
Enjoy,
Gary
=========================
Run this code in each system. BTW, I believe you can put this into
an "Includesystem" and pass the MySysNum value as a parameter, but I
don't usually use "Includesystem"s so I'm no expert there. I've
written this code assuming you do that. If it turns out that doesn't
work, you can move the MySysNum value back into the Constants section.
Inputs: MySysNum(0);
{ This code stores the closed equity for N systems.
All equity values for the same bar are stored contiguously, e.g.:
(Base) (Base+1) (Base+Offset)
Marker StartDate Sys0Bar1 Sys1Bar1 ... Sys0Bar2 Sys1Bar2 ...
All told, the data array uses up NSys*maxdays+Offset memory
locations. NSys and Offset are defined in the Constants
section below, and "maxdays" is the maximum number of days
(NOT bars) spanned by all of your systems. I.e. it is the
last day found in any system, minus the start date of System 0.
System #0 is the "master" system, and it must be run *before*
all other systems. Its starting date is stored as the starting
date for the equity data, and all other systems key off that date.
No system should have a starting date earlier than System #0
(because it will result in rather skewed equity figures) but
the code shouldn't bomb if one does.
Set the system ID for each system in the MySysNum input value.
Make sure that each system has a unique ID value, using 0 for the
"master" system and 1 through NSys for the others.
}
{ Constants:
NSys: number of systems to be combined
Base: location in global memory to store the system data
Offset: # slots of "overhead" memory before data array
MinPerDay: # minutes per day (duh :-)
}
Vars: NSys(10), Base(1000), Offset(2), MinPerDay(1440);
Vars: Marker(0), NowDate(0), StartDate(0), SysEquity(0);
{ Get current date. Store base date in global memory,
just before the array of system data.
}
NowDate = DateToJulian(Date);
if (CurrentBar = 1) then begin
{ "Master" system stores the date; all others read that date }
if (MySysNum = 0) then begin
StartDate = NowDate;
Marker = 112233 - StartDate;
Save_TS_Data(Base, Marker);
Save_TS_Data(Base+1, StartDate);
end
else begin
Load_TS_Data(Base, &Marker);
Load_TS_Data(Base+1, &StartDate);
{ Clear StartDate if no valid Marker found }
if (Marker <> 112233 - StartDate) then StartDate = 0;
end;
end;
{ Store the system equity values once per day.
Must check for StartDate <> 0 because TS sometimes doesn't
set CurrentBar = 1 until the 2nd or 3rd bar !!
StartDate <> 0 also blocks access to global memory
if Marker hasn't been set by System 0.
Check for NowDate >= StartDate in case system #N has
an earlier start date than System 0.
}
if (StartDate <> 0) and (NowDate >= StartDate)
and (Date <> Date[1]) then begin
TimeIndex = NowDate - StartDate;
Sys Equity = I_ClosedEquity;
{ Or use I_OpenEquity if you prefer }
Save_TS_Data(Base + Offset + Nsys*TimeIndex + MySysNum, SysEquity);
end;
======================
In the EquityCurve indicator:
Vars: NSys(10), Base(1000), Offset(2), MinPerDay(1440);
Vars: NowDate(0), StartDate(0), SysNum(0),
SysEquity(0), Eq(0), MaxEq(0);
{ Get current & base date. }
NowDate = DateToJulian(Date);
if (CurrentBar = 1) then begin
Load_TS_Data(Base, &Marker);
Load_TS_Data(Base+1, &StartDate);
{ Clear StartDate if no valid Marker found }
if (Marker <> 112233 - StartDate) then StartDate = 0;
end;
{ Retrieve equity for each system for this day, sum & plot }
if (StartDate <> 0) and (NowDate >= StartDate)
and (Date <> Date[1]) then begin
TimeIndex = NowDate-StartDate;
SysEquity = 0;
for SysNum = 0 to NSys-1 begin
Load_TS_Data(Base + Offset + Nsys*TimeIndex + SysNum, &Eq);
SysEquity = SysEquity + Eq;
end;
end;
if (SysEquity > MaxEq) then MaxEq = SysEquity;
Plot1(SysEquity, "Equity");
Plot2(MaxEq, "Max Equity");
|