MultiSystem V1.1 Help
MultiSystem V1.1
Introduction
Components
Usage
Changes/additions
from previous releases
Implementation
Filtering
features
Trade
filtering
Symbol
filtering
Position
naming methods
Samples
Limitations
Miscellaneous
Credits
Disclaimer
Appendix
System
template
Using a combination of
trading systems can provide an extra level of diversification which could result
in a better risk/reward ratio, a smoother equity curve and as a result, a more
profitable trading.
MultiSystem is a framework
for combining multiple script written for Wealth-Lab © into aggregated trading
systems, thus allowing developers to test ideas that previously were difficult
to implement.
MultiSystem also extends
some of the built-in WealthScript functions and provides systems developers with
more flexibility by allowing them to adapt some of these functions to their
specific needs.
In order to be run within
MultiSystem, individual scripts need a small number of cosmetic changes
described in the sample template.
It is recommended that
Version 1.1 be used with Wealth-Lab Build 49 or later.
- MultiSystem
V1.1 – the entry point in the MultiSystem V1.1 framework
- MultiSystem
V1.1 Positions - positions classes and methods
- MultiSystem
V1.1 FX - helper classes
- MultiSystem
V1.1 Master Sample – the main entry point for the sample
- MultiSystem
V1.1 System1 – 3 – the 3 sample systems derived from: “Stochastic
Price Reverse – market V4.5”, “Basic
pullback buyer” and “RSI with ADX filter & ATR”.
- MultiSystem
V1.1 Filtered System - helper class for creating systems that support order
and/or symbol filtering.
- MultiSystem
V1.1 Template – template indicating the steps needed to create or adapt a
script for MultiSystem. This template is also added as an appendix to this
document.
- SymbolsList
– utility module that implements functionality needed by the symbol filter
- File
– utility module that contains the class File, an encapsulation of the
file functionality in Wealth-Lab.
In order to use MultiSystem
V1.1, you have to download all the scripts that comprise this framework from the
web site into Wealth-Lab Develper. In order to run the sample and use the symbol
filtering capabilities you will need to create a file containing a list of symbols and save it on the
hard drive. This file is used to create a virtual sub-WatchList (see below).
This list of symbols should be a subset of the symbols in the WatchList that the
MultiSystem will be run on. The name of this file then needs to be passed in the
CreateWithSymbols method call in Sample3.
Here
is a link to the MultiSystem page on the Wealth-Lab web site
Compared with previous
releases, V1.1 implements the following:
- wrong
number of open positions reported in some cases – fixed. Thanks map@w-l
for reporting it and suggesting a fix.
- wrong
entry/exit levels for some trades with slippage on, when using Installxxx/ApplyAutoStops
functions – fixed
- other
minor fixes
- New
methods implemented: SellAtTrailingStop and CoverAtTrailingStop, introduced
in Wealth-Lab Build 46.
- All
Buy/Short/Sell/Cover methods return a boolean within MultiSystem as even
AtMarket or AtClose orders may not be executed, either because a filtering
(see below) or because of slippage. Built-in AtMarket and AtClose
WealthScript functions currently do not return a boolean value.
- The
methods getPositionGlobalIndex and getActivePositions have been exposed. The
first converts a per system position index into a global position index, and
the second returns a handle to to a list of open positions.
- A
new File class was added to the package, which encapsulates the file
functions in WealthScript. This class is in a separate script and is used by
the SymbolsList class, which implements the filtering by symbol, but can be
used as a standalone class.
- Replaced
global filters on all Buy and Short methods with individual filter methods
for each of the Buy/Short/Sell/Cover methods. This allows for a finer tuning
of scripts that use such filters. All these filters are members of the class
Positions, and are inherited by the abstract class System and accessible
within concrete classes derived from it. They can be used either directly in
a concrete system class or in an intermediate filter class, sitting between
the abstract System class and the concrete implementation of a specific
system class. See the SystemFilter class for an example.
The basic idea of
MultiScript is to create a layer of indirection between individual scripts and
the global Wealth-Lab position management functions. On the side of scripts,
this layer allows modified scripts to act as though they were running in a
“virtual” Wealth-lab environment, without knowledge of positions opened or
closed by other scripts. For example, LastActivePosition will return the last
active position for the system calling it or ApplyAutoStops will only close
positions opened by the current script.
The implementation takes
advantage of the name resolution scheme in the WealthScript language. If there
are two functions, one global, and the other member of a class, objects of that
class will always call by default the member function. So I created a base class
Positions that implements methods with the same names and arguments as the WL
global position management functions, which after doing their internal
processing, call the global methods with the same name. This way, system classes
derived from this base class, will always call the per-instance methods rather
than the global ones. The advantage of this approach is that most scripts will
not need any structural changes.On the side of WL position-management functions,
the layer makes the calls as though all the different systems were one system.
Each system must then implement the virtual function “runByBar” declared in
the System base class, which does the processing for one bar. This functions are
then called polymorphically, in turn for each system, by the MultiSystem class,
which coordinates the whole process.
By default, no files are created or accessed at runtime. There is a filter class
that allows one to read a file defining sub-watchlists, so that each system can
then be run on a different set of symbols, but using it is optional.
The samples and template
provided illustrate how to adapt existing systems to be used within MultiSystem
MultiSystem allows one to
write filtering classes and/or methods separate from the trading system itself,
thus enabling code reuse, modularity, event driven functionality, a cleaner
code, this with no changes to the original script.
The filters can be
implemented in the system itself, or in an intermediate class derived from
System, and which can be used as base class by multiple systems, thus allowing a
cleaner code and reuse between these. This latter was the approach taken in
implementing the class FilteredSystem.
It has to be noted that
there is a performance penalty that has to be paid for these features to work,
so simulation will be somewhat slower.
There are two types of filters that can be applied: trade filters and symbol
filters.
The filtering methods are
called before the Wealth-lab position entry/exit functions are called. The
general rule is that if the filter returns true, the execution continues, if it
returns false, the entry/exit method returns with a value of “false”, thus
indicating that the trade has not been entered.
Here are the prototypes for
all the filter methods that can be used in an intermediate filtering class or a
system class. FilteredSystem illustrates their use.
function buyAtCloseFilter( Bar : integer;
SignalName : string ) : boolean; virtual;
function buyAtLimitFilter( Bar : integer; LimitPrice : float;
SignalName : string ) : boolean; virtual;
function buyAtMarketFilter( Bar : integer; SignalName : string ): boolean; virtual;
function buyAtStopFilter( Bar : integer; StopPrice : float;
SignalName : string ): boolean; virtual;
function shortAtCloseFilter( Bar : integer; SignalName : string ) : boolean; virtual;
function shortAtLimitFilter( Bar: integer; LimitPrice: float;
SignalName: string ): boolean; virtual;
function shortAtMarketFilter( Bar: integer; SignalName: string ) : boolean; virtual;
function shortAtStopFilter( Bar: integer; StopPrice: float;
SignalName: string ): boolean; virtual;
function coverAtCloseFilter( Bar, Position : integer; SignalName : string ) :
boolean; virtual;
function coverAtLimitFilter( Bar : integer; LimitPrice : float;
Position: integer; SignalName : string ) : boolean; virtual;
function coverAtMarketFilter( Bar, Position : integer; SignalName : string ) :
boolean; virtual;
function coverAtStopFilter( Bar : integer; StopPrice: float;
Position : integer; SignalName : string ) : boolean; virtual;
function sellAtCloseFilter( Bar, Position : integer; SignalName : string ) :
boolean; virtual;
function sellAtLimitFilter( Bar : integer; LimitPrice : float;
Position : integer; SignalName : string ) : boolean; virtual;
function sellAtMarketFilter( Bar, Position : integer; SignalName : string ) :
boolean; virtual;
function sellAtStopFilter( Bar: integer; StopPrice: float;
Position: integer; SignalName: string ): boolean; virtual;
function sellAtTrailingStopFilter( Bar: integer; Stop: float;
Position: integer; SignalName: string ): boolean; virtual;
function coverAtTrailingStopFilter( Bar: integer; Stop: float;
Position: integer; SignalName: string ): boolean; virtual;
|
Allows each and any of the
component systems to be run on different subsets of symbols of the WatchList
that the MultiSystem is run on.
Symbol filters create
virtual sub-watchlists that can be defined on a per system basis. The
MultiSystem V1.1 Filtered System implements such a filter using the SymbolList
class. This is done by creating a WatchList in WL and defining subsets of
symbols of this WatchList for each system. These list should be in text files on
disk, with symbols separated by space or new line characters
Sample 3 illustrates how to use symbol filtering. The way to achieve this is by
calling this inherited constructor CreateWithSymbols in the FilteredSystem
class:
inherited CreateWithSymbols( leadBars, systemName, symbolFileName );
|
where leadBars and systemName have the usual
meaning, and symbolFileName is the name of a text file with the list of symbols
this system is meant to use.
Example of the contents of a symbols file:
|
aol
csco cmrc yhoo msft
arba ibm
amzn T INTC
|
MultiSystem V1.1 implements
5 methods in the class System that append or prepend strings to trade names
generated by each system. As these strings are displayed in the $imulator and
scan tool, a user can sort the trade list by system name.
By default, if none of the
following methods is called, the system name passed as argument to the System
class constructor will be prepended to all the trade names generated by the
system. A ':' character is used as separator. If the system name or user
defined string are empty, only the trade name will be shown.
Here are the prototypes and
short description of these methods: (here
you could add an example for each effect )
|
// appends
the system name (passed as an argument
// to the
System class constructor) to trade names
//
generated by this system.
procedure System.appendSystemNameToTradeName;
// prepends
the system name to trade names generated by this system.
procedure System.prependSystemNameToTradeName;
// appends
a string to trade names generated by this system
procedure System.appendStrToTradeName( str : String );
// prepends
a string to trade names generated by this system
procedure
System.prependStrToTradeName( str : String );
// resets
the user defined string - no more string
// will be
appended or prepended to trade names after this call
procedure
System.resetAppendPrependName;
|
A number of sample scripts
are also included, which illustrate the concepts.
MultiSystem V1.1 System
Template illustrates the steps that a developer needs to take in order to create
a new system or adapt an existing one for use with MultiSystem.
MultiSystem V1.1 Master
Sample, FilteredSystem, Sample1, Sample2 and Sample3 are the components needed
to run the sample. Master Sample is the entry point, FilteredSystem is an
implementation of a filter class, that contains trade filters as well as symbol
filters, and Sample1 to 3 are the 3 individual systems to be combined. In order
for this sample to run, SymbolsList and File are necessary. Also, a file
containing a list of symbols needs to be created and its name passed as an
argument in the constructor of System3, which is the only one that uses a symbol
filter.
MultiScript based system
will run slower than their non-MultiScript counterparts, due to the multiple
levels of indirections and using object oriented features such as inheritance,
encapsulation and polymorphism in an interpreted language.
MultiSystem duplicates some
of the Wealth-Lab native functionality and simulation and scans results are
identical within the limits described elsewhere in this document between the two
as of Wealth-Lab Developer build 49. This may not hold true for future builds. Please report any
such differences.
I tested MultiSystem using
individual and combined scripts and compared the statistics with the original
systems and there were no differences in results with or without slippage (see limitations).
I have not tested it with
adaptive scripts or other more complex ones, although they should be able to
take advantage of the MultiSystem framework if they are modified appropriately.
This system cannot be run
on the web site as it uses include directives {I ‘xxx’} which don’t work
there, but it will work fine on your desktop version of WealthLab Programmer
MultiSystems can be run
within the Scan tool to generate alerts like any other system. There is a
difference however – MultiSystem will generate an alert for each position that
is open at the last bar, as opposed to Scan on regular systems, which will only
generate one alert for multiple open positions for the same symbol.
Thanks map@w-l for
testing MultiSystem and giving me feedback on some bugs and even suggesting a
fix.
Appreciation goes to rickty
for publishing Stochastic Price Reverse – market V4.5 and Basic
pullback buyer and dmacdonal9 for publishing RSI with ADX filter
& ATR, the three scripts I used as samples.
I have worked hard on
ensuring that this script does what is supposed to do reliably and accurately,
but one never knows…
Although I run a whole set
of tests and have been using it myself, there may be still bugs that may result
in inaccurate results or other yet unknown issues. Please let me know of any
problems you may encounter while using it, and I will do my best to fix them.
Please acknowledge that by
using the MultiSystem framework, you accept that I, Adrian Michel, its
developer, cannot be held responsible for any financial losses or other bad
things that may result from its use. Use at your own risk.
This template shows the
steps that need to be taken in order to update an existing system or create a
new system compatible with MultiSystem.
This template is also
provided separately as a script.
//***************************************
//
MultiSystem V1.1 System Template
//
// Adrian
Michel 2002, 2003
//***************************************
//***************************************
// This
portion (1-8) shows how to change a system to make it compatible with
MultiSystem V1.0
//***************************************
// (1) This
line includes the MultiSystem classes and makes them visible locally.
//
It may not be necessary, or may even lead to multiple definitions in
case
//
there is a master system including all the separate components.
{$I
'System'}
// (2)
Start class definition that will become the new system class.
//
Note the syntax indicating that the new class is derived
//
(or inherits from) the class System, defined in MultiSystem V1.0.
type
System1 = class( System )
private
// (3) All
the variables used by the system become data members of the new class.
//
They can be declared private (preferred), which allows for better
encapsulation.
//
Also, they do not need to be prefixed by the “var” keyword.
constructor
Create;
// (4)
Declaration of the two main methods: the constructor Create, and runBar.
//
Create is the class constructor, and RunBar is a method that overrides
//
an abstract method with the same name in the class System. This allows
//
for the polymorphic behavior, where the MultiSystem class can run any
//
system class, as long as it is derived from System, the only class
//
MultiSystem knows of.
protected
procedure runBar( Bar : integer );override;
// (5)
Optional - declaration of various filtering methods
//
The default behavior is 'on', so if these filters are not overriden,
//
they will not have any effect
//
If they return false, the buy/sell/short/cover order will not be
entered, fact which can be
//
tested using the return value for these methods (in MultiScript, even
atmarket and atclose
//
orders return a boolean value, to indicate whether the position was
opened or not.
//
Here are only 2 of the many possible filters
function
buyAtCloseFilter( Bar : integer; SignalName : string ) : boolean; override;
function
buyAtLimitFilter( Bar : integer; LimitPrice : float; SignalName : string ) :
boolean; override;
// (7)
called with a symbol name - if Result is true, the system will be run
//
on this symbol, false otherwise. This can be used in conjuction with
the
//
SymbolList class to create virtual sub-watchlists
function symbolFilter( symbol : String ) : boolean; override;
// (8) end
of class definition
end;
// (9)
Definition of the constructor Create. This is implemented as a regular
//
procedure prefixed by the class name, and contains all the
initialization
//
code (all the code that is between the variable declaration and the
main
//
Bar loop, in a typical system).
constructor
System1.Create;
begin
// (10) The
constructor needs to call the base class (System) constructor with
//
two parameters: number of lead bars and the system name.
inherited Create( leadBars, systemName );
end;
// (11)
runBar contains the main bar loop, where trades are generated.
//
It does not need the ‘for’ statement, as this method will be called
//
from within MultiSystem for each bar.
procedure
System1.runBar( Bar : integer );
begin
end;
// (12)
implementation of the buy at close filter - see FilteredSystem V1.1 for a
usage example
//
This implementation returns true
function
System1.buyAtCloseFilter( Bar : integer; SignalName : string ) : boolean;
override;
begin
Result := true;
end;
// (13)
implementation of the buy at limit filter - see FilteredSystem V1.1 for a
usage example
//
This implementation returns true
function
System1.buyAtLimitFilter( Bar : integer; LimitPrice : float; SignalName :
string ) : boolean; override;
begin
Result := true;
end;
// (14)
implementation of the symbol filter - see FilteredSystem V1.0.2 for a usage
example
//
This implementation returns true
function
FilteredSystem.symbolFilter( symbol : String ) : boolean;
begin
Result := true;
end;
//********************************************
// This
portion shows how to write the multisystem part, where all the individual
// systems
will be integrated and run as one. The systems and the master system
// will
typically be implemented as different scripts
//********************************************
// (15) a
variable of type MultiSystem is created
var ms : MultiSystem;
// (16) a
MultiSystem object is created
ms := MultiSystem.Create;
// (17)
variables of types of different systems are declared
var sys1,
sys2, sys3 : System;
// (18) the
system objects are created
sys1 :=
System1.Create;
sys2 :=
System2.Create;
sys3 :=
System3.Create;
// (19) the
systems are made known to MultiSystem
ms.addSystem(
sys1 );
ms.addSystem(
sys2 );
ms.addSystem(
sys3 );
// (20)
MultiSystem is run by bar (there could be other ways,
//
such as running all the bars in one system, going to the next etc.
ms.runByBar;
// (21)
free all the objects and resources used by the script.
ms.Free;
|
Copyright (C) Adrian Michel 2003
|