Optimization Seminar PDF

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 79

Optimization 201

Bruce Robinson
brobinson@zwave.net

March 11, 2006

Presentation Overview

Optimization 101 Review


Signal Forms
How the Amibroker Backtester Works
Selection, Timing, and Trading Variables
Using the Optimize Function
How the Intelligent Optimizer works
IO Directives and Options
Example 1 tuned sector trading system
Example 2 weighted position portfolio system
Methodology and Conclusions

Optimization 101 Review

Why do we model, backtest, and


optimize

Model

Back-test

To define an edge in timing, selection, money


management
A model approximates history
Accuracy is required, but not exactness
To verify that edge, know the odds
To test across different markets
To provide confidence going forward

Optimize

To maximize or minimize those factors that are


most important
CAR, MDD, Sharpe, UPI, etc.
The combination is called fitness

Back-testing
???

2001

2003

TODAY

BACKTEST AND
OPTIMIZE

Big Question What percentage of the


back-test return, MDD, etc. should you
expect going forward ?

The back-fitting sensitivity


problem -

Other issues

Back-testing

Different market action vs. recent


market action

Number of signal samples - statistical


significance

Test over bull, bear, sideways markets

Issue for intermediate term systems

Survivorship bias
Bad performing stocks fold, or merge
Good funds record is bought
Bad funds record is buried

Selection bias

AI optimization

AI optimization offers many new


capabilities
To date we have fitted as much data as
possible and hoped
Mechanization is one of the most
important capabilities

Eliminates biases - selection, event knowledge,


etc.

Less sensitive solutions can be found for a


point in time
We can time travel to points in the past
and look at walk forward performance
A spliced equity curve can be assembled
to look at what would have happened if

Keywords

Near optimal
Robust
Out of sample, walk-forward

Near optimality -

Robustness -

Rolling walk forward


testing

1998

2000

2002

TODAY

Green segments represent equity that


COULD have been achieved !

Anchored walk forward


testing

1998

2000

2002

TODAY

Green segments represent equity


that COULD have been achieved !

Goals and penalties

Goal assigns a minimum desired value to a


fitness field name (AB optimization result
column)
Values below the goal result in an
adjustment factor that is applied to fitness.
Two types of scaling multiplier and
exponential
Example of multiplier

Fitness is UPI
UPI of solution point = 2
CAR = 15, CAR goal = 20
Fitness adjustment is .75 * 2 = 1.5

Sensitivity

Definition - change in fitness with


respect to distance from solution
Rationale since change in inputs
cant be accurately predicted,
approach is to measure change in
output based on change in
parameters
An average percentage is
determined based on samples
The solution point fitness is adjusted
by a sensitivity goal

The sensitivity adjusted


fitness -

Signal Forms

Amibroker signals

Trading signal logic in Amibroker


involves basic Boolean logic
Signals can be in two forms level
and impulse
But, it also involves manipulation of
signal state
This results in many special cases
Rather than try to detail these cases,
guidelines will be offered to avoid
them

Boolean logic Amibroker

There are a few special considerations for


Boolean logic in Amibroker
In AB, the value 0 is FALSE, any other value
is TRUE
Boolean logic is most often applied to a
vector
Boolean logic where Nulls are involved are
special cases

True AND Null = False


True OR Null = True
NOT Null = Null

Why is this important

It allows indicators derived from tickers that


start at different dates to have Boolean

Impulse form examples

One bar event Cross() function at 50 level of


Stochastic

Data by

Impulse form

Impulse form can be thought of as an


event
Also, think of impulse form as the
leading edge of the level form
It is generated by functions that
detect events such as Cross()
It becomes very useful in generating
trading signal combinations

The need for state

What is state ?

Main reasons why it is needed ?

It is a form of digital memory


It retains that value of the last Buy or Sell
impulse signal
It is usually in level form
Not all signal conditions can be described by
Boolean logic
In certain situations, redundant signals are
desirable

Lets look at examples of each

Example 2 of state
requirement

Take the earlier example, but of a stochastic, but


Buy on going up thru 60 and sell on going down
thru 40 can you describe the area between 40
and 60 with a Boolean statement ?

Data by

Example 2 of state
requirement

For example, the Buy or Sell result of a


stochastic of 50 depends on how you got there

Data by

State and Impulse Form

Since there are two forms of signals,


how do we get from one form to the
other
Flip() is used to implement the state
memory
The output of Flip() is a level signal

State and Impulse Form

ExRem( Array1, Array2 ) is used to


convert from state form to impulse
form
From the Amibroker help

removes excessive signals:


returns 1 on the first occurence of "true" signal in Array1
then returns 0 until Array2 is true even if there are "true"
signals in Array1

The output of ExRem() is an impulse


signal

Guidelines for combining


signals

These guidelines have an overall goal of


keeping as many redundant signals as
possible

Perform the And operation in level/state form


Perform the Or operation in impulse form
Not operation should be done in level/state
form
Postpone the Flip() that is used to get state
form as long as possible
Try to make buy and sell signal combinations
symmetric to minimize lockup

How the Amibroker


Backtester Works

Backtester(s)

There are really 3 types of current


backtesters in Amibroker
Individual issue
Portfolio trading with signals
Portfolio trading with rotation

Plus the Old backtester


It is important to first decide on your
goal

Functional
considerations

The AFL program will have at least one


execution per issue
There may be other executions if
parameters are involved, for example.
If the custom backtester is enabled, it will
have a final post-processing pass that can
interface to the backtesting engine and its
objects
The equity and stats results are not
available until the backtester is complete

Data flow model


Data initialization

Automatic
Analysis
Code

Back-Tester

RESULTS

All

Current

Stocks

Stock

Filter

Portfolio backtester

The backtester can be used to


perform selection and timing on a
filter list on input issues
Number of positions and position size
can be specified
The condition of buys for more than
the number of positions must be
resolved
PositionScore can be used to assign
priorities
Only evaluated at the buy impulse for

www.amibroker.com/gifs/bt_regular.gif

Selection, Timing, and


Trading Variables

Boilerplate 1 settings
code //EnableRotationalTrading();
BuyPrice = SellPrice = ShortPrice =
CoverPrice = Open;
SetTradeDelays( 1, 1, 1, 1 );
SetFormulaName("TEST");

Boilerplate 2 settings
code SetOption(
SetOption(
SetOption(
);
SetOption(
);

"InitialEquity",
"MinShares",
"MinPosValue",

1000 );
.0001 );
0

SetOption(
SetOption(
);
SetOption(
SetOption(

"AllowPositionShrinking",
"ActivateStopsImmediately",

True

);
True

"ReverseSignalForcesExit",
"AllowSameBarExit",

True
True

);
);

"FuturesMode",

False

Boilerplate 2 code
considerations

Initial equity needs to be large enough to


accommodate MinShare and number of positions
AllowPositionShrinking is usually enabled to allow
the buy less than the PositionSize and to account
for round-off error
ActivateStopsImmediately has some interactions
with other settings and will be explained in detail
later
ReverseSignalForcesExit allows for long/short
switches without an explicit Sell of Cover
AllowSameBarExit can be used for single day
trade, but is also useful for special purposes

Boilerplate 3 settings
code SetOption(
);
SetOption(
0
);
SetOption(
0
);
SetOption(
100
);
SetOption(
);
SetOption(
);
SetOption(
True );
SetOption(
);

"CommissionMode",

"CommissionAmount",
"InterestRate",
"MarginRequirement",
"MaxOpenPositions",

"WorstRankHeld",

"PriceBoundChecking",
"UsePrevBarEquityForPosSizing",

True

Boilerplate 3 code
considerations

Commission mode should be modeled as


closely as possible, but is usually no longer
a major consideration
Percentage commission can be used to
model slippage
Interest rate is fixed for the MM (Sell,
Cover) position
Margin requirement is the percentage of
initial equity required. It is applied when
PositionSize <= 100 which may be a
modeling consideration
MaxOpenPositions applies to the Portfolio
backtester

Boilerplate 3 code
considerations

WorstRankHeld applies to rotational


mode and refers to the rank below
which a current position is sold
PriceBoundChecking is a special
consideration if you want to
manipulate the trade price arrays
outside of the bar limits
UsePrevBarEquityForPosSizing is selfexplanatory, and is the typical mode
for re-balancing used in fund
portfolios

Boilerplate 4 settings
code MaxPos

= 100 * 100 /

RoundLotSize
TickSize
MarginDeposit
PointValue

= 0;
= 0;
= 0;
= 1;

GetOption("MarginRequirement");
PositionSize
= -MaxPos /
GetOption("MaxOpenPositions");
// 0 for Funds, 100 for Stocks
// 0 for no min. size
// For futures

ExitAtTradePrice
= 0;
ExitAtStop
= 1;
ExitNextBar
= 2;
ApplyStop( stopTypeLoss, stopModeDisable, 0,
ExitAtTradePrice );
ApplyStop( stopTypeProfit, stopModeDisable, 0,
ExitAtTradePrice );
ApplyStop( stopTypeTrailing, stopModeDisable, 0,
ExitAtTradePrice );
ApplyStop( stopTypeNBar, stopModeDisable, 0,

Boilerplate 4 code
considerations

PositionSize is coded to account for


margin
RoundLotSize is typically 0 for funds
and 100 for stocks, although odd-lots
are not that un-economical and
fractional stock shares are possible
at one brokerage
A detailed explanation of stops is
beyond the scope of this talk

The main point to remember is that they

Using the Optimize


Function

The Optimize Statement

The general form of the optimize


statement is
variable = Optimize( description ID, default, min, max,
step )

When multiple optimize statements are executed


by the Optimize function

A pass of the AFL code is made for each possible


combination

For example
x = Optimize( X, 5, 1, 10, 1 );
y = Optimize( Y, 50, 100, 1000, 100 );

Passes
( 1, 100 )
( 1, 200 )
etc.

The Optimize Statement

Anything that can be represented by a


number can be assigned to an Optimize()
function result !

Parameters to functions
True/False (1/0) to gate a condition
Comparison to Status(stocknum) to choose
from watchlist
SetOption() parameter
PositionSize

Optimize() parameters are cached they


are not dynamic

The Optimize Statement

Guidelines

Variables that are unique to tickers in a


watchlist must be defined separately
Variables have no knowledge on each other

So, there is no way to limit the total of N parameters


to a maximum
For example,
Individual PositionSize variables for each ticker
cannot be calculated directly
They are coded as weights that may vary from 0
to 100
The sum is calculated
The scaled value for each ticker is its position size

How the Intelligent


Optimizer Works

What IO does the


details

IO generates a number of tuples of


variable combinations that are designed to
explore the problem space

For example
( 2, 200 )
( 3, 200 )
( 2, 300 )
etc.

It replaces each call to Optimize() with a


call to IOptimize()
IOptimize() returns the value of each
variable in the tuple

What IO does the big


picture

IO must drive Amibroker from an


outside script
Creates a modified version of the AFL
to perform housekeeping and call
IOptimize()
Invoke the Optimize function
repeatedly to test a set of tuples
Analyze the set results to guide the
next search iteration

IO Directives and
Options

IO directives for traditional


optimization
//IO: StatusWindow: N
//IO: SaveCancelled: Y

Disable the
directive
// Remove in final "production" run
//xIO: FitnessTime: 300
5 minute
//xIO: SenFinalTests: 1000
limit
1000 samples for
sensitivity
Penalize result < 85%
//IO: SenOptGoalPct: 85
sensitivity
//IO: SenOptTests: 10
10
samples to determine
//IO: Fitness: UPI
sensitiviy
CAR goal to prevent high
//IO: Goal: CAR: 15
UPI, low CAR
//xIO: BegISDate: 01/01/1995
//xIO: EndISDate: 01/01/2001
Walk-forward directives
//xIO: EndOSDate: 9/15/2005
disabled
//xIO: WFAuto: Anchored: Every: Year

Example of a Tuned, Sector


Trading System

Sector Trading

Elevator pitch
Buy a sector fund when it reaches its
N day low
Hold for a minimum of H days
Take profits when it reached P percent

This is an oversold strategy


Works well in non-bear markets
BUT, it is a filter tuned to the swing
cycle frequency and the volatility

Sector Trading Code //IO: SenOptGoalPct: 85


//IO: SenOptTests: 10
//IO: Fitness: CAR
//xIO: Goal: CAR: 15
//xIO: BegISDate: 01/01/1995
//xIO: EndISDate: 01/01/2001
//xIO: EndOSDate: 9/15/2005
//xIO: WFAuto: Anchored: Every: Year
HoldDays

= Optimize( "HoldDays", 10, 2, 12, 1 );

ProfitStop

= Optimize( "ProfitStop", 5, 2, 12, 1 );

Sector Trading Code ExitAtTradePrice


= 0;
ExitAtStopIntraDay = 1;
ExitAtStopNext
= 2;
ApplyStop(stopTypeLoss, stopModeDisable, 0,
ExitAtTradePrice);
ApplyStop(stopTypeProfit, stopModePercent, ProfitStop,
ExitAtStopNext);
// ExitAtTradePrice for same day
ApplyStop(stopTypeTrailing, stopModeDisable, 0,
ExitAtTradePrice);
ApplyStop(stopTypeNBar, stopModeBars, HoldDays,
ExitAtTradePrice); //ExitAtStopNext);
NumDays

= Optimize( "NumDays", 10, 10, 20, 1 );

LowDays
= IIf( LLV( C, NumDays ) == C, 1, 0 );
Buy
= LowDays;
Sell
= 0;
// Will be exited by N-bar stop or by
Profit target
Short
= Cover = 0;

Optimization Net Profit from 4/1/03 -

Optimization Net Profit from 4/1/00


with 03 parms -

Optimization Net Profit from 4/1/00 -

Optimization CAR/MDD from 4/1/03 with


IO -

Optimization CAR/MDD from 4/1/ 00


with 03 parms and IO -

Sector System Optimization


Summary

( HoldDays, ProfitStop, NumDays )


Amibroker optimized from 4/1/03 on Net
Profit
( 8, 10, 11 )
Amibroker optimized from 4/1/00 on Net
Profit
( 5, 6, 10 )
IO optimized from 4/1/03 on CAR/MDD
( 6, 5, 18 )

Optimization CAR/MDD from 4/1/ 03

Optimization CAR/MDD from 4/1/ 03

Optimization CAR/MDD from 4/1/ 03

Optimization from CAR/MDD 4/1/ 03


with IO -

Sector Trading.afl

Implements this sector trading


system
Runs against a watchlist of sectors

Profunds Sectors Japan-Europe.tls

Program and watchlist will be posted


to site
Play with it !

Example os a Portfolio
Optimization System

The main portfolio


problem

How to optimize the the PositionSize


for each ticker
Lets say the we have 5 long tickers,
and we want to optimize the portfolio
percentages in a hedge
Hedge percentage is 30%
Long percentage is 70%

Percentages of 5 long tickers must


add to 70%
Issue is that variables are
independent

A solution

This design pattern is known as normalizing


First, we optimize weightings
fund1wt
100, 1 );
fund2wt
100, 1 );
fund3wt
100, 1 );
fund4wt
100, 1 );
fund5wt
100, 1 );

= Optimize( "fund1wt", 10, 0,


= Optimize( "fund2wt", 10, 0,
= Optimize( "fund3wt", 10, 0,
= Optimize( "fund4wt", 10, 0,
= Optimize( "fund5wt", 10, 0,

A solution

Next, we get the sum of the weights


fundwtsum = fund1wt + fund2wt + fund3wt + fund4wt +
fund5wt;

Then, set the total percentage of the long funds


fundpcnt

= 70;

Lastly, we normalize the percentages


fund1pcnt
fund2pcnt
fund3pcnt
fund4pcnt
fund5pcnt

= fund1wt / fundwtsum * fundpcnt;


= fund2wt / fundwtsum * fundpcnt;
= fund3wt / fundwtsum * fundpcnt;
= fund4wt / fundwtsum * fundpcnt;
= fund5wt / fundwtsum * fundpcnt;

Why it works

The weights are all allowed to vary over the same


range
IO optimizes the weights based on the
percentages assigned to PositionSize
if ( Name() == fund1 )
PositionSize
if ( Name() == fund2 )
PositionSize
if ( Name() == fund3 )
PositionSize
if ( Name() == fund4 )
PositionSize
if ( Name() == fund5 )
PositionSize

= -fund1pcnt;
= -fund2pcnt;
= -fund3pcnt;
= -fund4pcnt;
= -fund5pcnt;

PortHedge2IO.afl

Portfolio and hedging optimization model


Originally presented in Clearwater in 2005
Has two modes

Finds near efficient frontier for up to 5 funds


Optimizes the mix for an augmented hedge
with up to 3 long funds, 3 short funds, and
money market

Designed to use IO
Uses FastTrack symbols
Hedging mode uses FastTrack based
signals

Methodology and
Conclusions

Steps of the
Methodology

Conceptualize

Code

Describe the system in an elevator pitch


Be aware of Amibroker backtester
considerations
Check the trades

Refine and optimize

Select in-sample data appropriate to the style


and time frame of trading
Identify the parameters and degrees of
freedom

Be aware of implicit constraints

Steps of the
Methodology

Analyze in-sample results


Perform sensitivity analysis
Analyze drawdowns and other factors
that would result in suspension of
trading

Decide if further testing is warranted


Dont be afraid to discard systems if
solutions to the identified issues are
elusive
Remember discarding an inferior
system frees up time to investigate
others that may prove superior

System Lifetime

Should systems work over different market


characteristics ?
If so, compromises are inevitable
Is it a viable strategy to target the system
to certain market conditions ?

If we can detect the transitions in market types


If we have a circuit breaker to suspend
trading

An approach to detection and suspension


is to trade the equity curve

Steps of the
Methodology

Perform walk-forward testing

Look for results that are less than optimized,


but within reason
Walk-forward frequency should be looked at as
an additional parameter

Re-optimization frequency is being identified


Dont assume that more is better
System stability with respect to re-optimization is an
issue

The future ain't what it used to be


Yogi Berra

Conclusion Tool are now available to optimize, evaluate, and


perform a walk-forward analysis dont accept less

You might also like