Australian (ASX) Stock Market Forum

qldfrog weekly Skate inspired system

Back to systems hard numbers:
only losses

Mr Skate experiment: hit quite hard:-$428 in first week (I did chase Myer as I wanted to stick to the system for compliance, unless the code is mandating purchase price can not be above 3% of last week close, which I do not believe is the case
Weekly QFDuc:-$706 but still positive on its 3rd week:

QFDuc started 1/05/2020
Total invested $ 90,009.85
Cash remaining $ 33,166.71
Current portfolio value $ 90,402.45
Profit $ 392.60
Nb of active positions 13
Nb max position 20
Return since start 0.44%
Annual return so far 11.37%
purchase value per position $4,520.12
Invested percentage 63%

Weekly ZLextra lost $244 but still positive
ZLExtra started 1/05/2020
Total invested $90,000.00
Cash remaining $59,073.80
Current portfolio value $90,408.21
Profit $ 408.21
Nb of active positions 7
Nb max position 20
Return since start 0.45%
Annual return so far 11.83%
purchase value per position $4,520.41
Invested percentage 35%

Paper traded daily behaving correctly so might start on monday
I will check tomorrow for next week action
 
here come the solution for a problem which was bothering me:
when we have a sell/by on open, we give a marging 2%, 3% from the last close, what if at open we are outside the margin, then the order will never pass yet our backtests we assume execution did happen and we purchased sold at open
Please find 2 piece of code to solve that:
1) computation of an actionable ASX rule compliant price:

//return the price as can be used on the asx for sell/buy based on asx increment rules
function GetASXPrice( rawPrice )
{
roundValue = round( rawPrice * 100 ) * 10;
leftOver = rawPrice * 1000 - roundValue ;//get tenth of cents value


res = IIf( rawPrice <= 0.1 , ( round( rawPrice * 1000 ) ), //0.1c increment
IIf( rawPrice >= 2 , ( round( rawPrice * 100 ) * 10 ), //1c increment
//otherwise 0.5c increment
Iif( leftover <= 2 , roundValue,
IIf( leftover > 7 , roundValue + 10, roundValue + 5 )
)
)
);
return res / 1000;
}

This is the result as displayed for explanation purpose in an explore result:
upload_2020-5-17_14-48-32.png

using a 3% buy sell margin:
AddColumn( IIf( Buy, GetASXPrice( ceil( C * 1030 ) / 1000), IIf( Sell, GetASXPrice( ceil( C * 970 ) / 1000 ), 0 ) ), "Offer ASX price ", 1.3, colorDefault , colorDefault , 80 );

:
 
And you should then ensure your backtests sell/buy will be executed..
let's add future looking code here so that we will get a match between backtest and our execution:


//check that in the next session day,
//the low will be lower or equal than our buy limit
//this is forward looking and used in backtests to ensure our real world order would be able to be executed
Buy =Buy AND (Ref(L, 1)<GetASXPrice(C*1.03));

and similar for the sell against the H of the day:

Sell = Sell AND (Ref(H, 1)>GetASXPrice(C*0.97));
Hope it helps

 
And you should then ensure your backtests sell/buy will be executed..
let's add future looking code here so that we will get a match between backtest and our execution:


//check that in the next session day,
//the low will be lower or equal than our buy limit
//this is forward looking and used in backtests to ensure our real world order would be able to be executed
Buy =Buy AND (Ref(L, 1)<GetASXPrice(C*1.03));

and similar for the sell against the H of the day:

Sell = Sell AND (Ref(H, 1)>GetASXPrice(C*0.97));
Hope it helps
Finally, this is not the ultimate solution: we pass an order for $2k for example but if the price is lower on open than at the close plus 3%, we will get less shares
By execution, we buy more shares going down than shares going up; not that great for a trend following system.....

ideally we should reverse engineer the broker code:
we do not buy $2k, we buy n shares with n*(C*1.03)=$2000; n stays constant, Open price on Monday just a guess (but can not be higher than C*1.03 to be considered in backtest)
Anyway, just not that critical at this stage
 
Also need to say I am going to start my daily system on Monday
52k start on the last 5y bactest:
upload_2020-5-17_15-20-47.png
Smoother than many of my weekly work and I like the behaviour in 2018, mid 2019 and recent crash.
Will not post daily nor even give regular weekly status but will keep you informed
 
I do not want to clutter DumpIt thread but I have some challenging data for @Skate (Mr Skate) and @Lone Wolf as well as hope many of the other followers
If a system tells you to jump in or out how important is it to follow the instructions when the Monday open is too high too low and you miss the auction open price
Well well many surprises:
Last week, following Mr Skate strategy trial, I chased Myer price my mistake, against the rules as below:
upload_2020-5-17_16-13-41.png
I then thought about this and used the code posted earlier with unexpected results:

An interesting point about the buy sell at open and 3% margin adopted:
I include that code in the 5y backtest of a daily strategy .it is scary:

First line:
without open margin check: we buy sell at open regardless of price



upload_2020-5-17_16-15-3.png

second line we only sell if within limit..well worse but not that bad, a sell at all cost is NOT that critical

third line: we ONLY buy within the 3% range: serious decrease

So, at least for that strategy, a buy at all cost on open is statistically VERY important, in that daily system nearly doubling the return on 5y whereas for the sell...

Food for thoughts as I was thinking intuitively the opposite: important to sell, not so much the buy..WRONG
 
In the dump it here thread I posted the logic I'd use to ensure amibroker bought at the same price we do.

Entry price for the purpose of determining the Qty of shares to buy = Close rounded up to 2 decimal places + 3%.
Qty shares to buy = your desired position size / Entry price as calculated above.

I think that part is pretty straightforward unless I've overlooked something. Not sure about the sell since you need to chase it if not filled at open. I appreciate your code, but don't understand it just yet as it uses functions I'm not familiar with. I'll have to look into it more.

First line:
without open margin check: we buy sell at open regardless of price

second line we only sell if within limit..well worse but not that bad, a sell at all cost is NOT that critical

third line: we ONLY buy within the 3% range: serious decrease

Depending on what your system looks for, possibly the best trades are the ones that gap up and never look back? That seems to be what your results are suggesting.

The problem is that we simply can't buy at open price if it gaps our limit order (except for the cases where they come back). So the question becomes how far can you afford to chase price before you become less profitable than line 3?
 
In the dump it here thread I posted the logic I'd use to ensure amibroker bought at the same price we do.

Entry price for the purpose of determining the Qty of shares to buy = Close rounded up to 2 decimal places + 3%.
Qty shares to buy = your desired position size / Entry price as calculated above.

I think that part is pretty straightforward unless I've overlooked something. Not sure about the sell since you need to chase it if not filled at open. I appreciate your code, but don't understand it just yet as it uses functions I'm not familiar with. I'll have to look into it more.



Depending on what your system looks for, possibly the best trades are the ones that gap up and never look back? That seems to be what your results are suggesting.

The problem is that we simply can't buy at open price if it gaps our limit order (except for the cases where they come back). So the question becomes how far can you afford to chase price before you become less profitable than line 3?
The initial function code i givetgive you what price you can use to get that 3% extra as asx has rules for increments
0.1c under 10c
0.5c until 2$
1c after

So this part is required and yes, we could compute the number of shares based on $ amount, brokerage and max price allowed based on the function.result
It is doable.
 
Cool, thanks.

I like what you did. While we were discussing whether it's important that the backtest matches, you tested to see how much difference it makes to your own system.
 
I want to stress that this difference istoward the extreme as these numbers are based on a daily, relatively high frequency system, a weekly trend system would probably not be that conclusive.i will check
 
I've done some dumb coding before and just made every buy/sell +3%. I had worse results but still within my own tolerances. As an even dumber coding move I actually over inflate my comissions which is probably why my live results are usually better than backtests.

I really like what you have done though. Good work.
 
busy day, I chased a few Gold miner purchases for my systems, made one mistake and will have to sell a ticker I bought twice....
Done 12 entries on the new daily system(fully invested).
Bought Mr Skate experiment packet; for the weekly:
QFDuc purchases 7 packets:
ANN
C:\Users\ThinkPad\AppData\Local\Temp\msohtmlclip1\01\clip_image002.gif
133 @$33.62
BKY
C:\Users\ThinkPad\AppData\Local\Temp\msohtmlclip1\01\clip_image002.gif
14062 @$0.31
DTL
C:\Users\ThinkPad\AppData\Local\Temp\msohtmlclip1\01\clip_image002.gif
969 @$4.64
OCL
C:\Users\ThinkPad\AppData\Local\Temp\msohtmlclip1\01\clip_image002.gif
619 @$7.10
RMS
C:\Users\ThinkPad\AppData\Local\Temp\msohtmlclip1\01\clip_image002.gif
2500 @$1.69
RRL
C:\Users\ThinkPad\AppData\Local\Temp\msohtmlclip1\01\clip_image002.gif
800 @$5.53
SAR
C:\Users\ThinkPad\AppData\Local\Temp\msohtmlclip1\01\clip_image002.gif
800 @$5.52
Gold heavy...
Sold
APT@$39.900
PNV$2.590(loss)
TNE$9.510
For a total profit of $223 on the sales
18 out of 20 positions are filled
ZLextra:
quieter: bought NEW 41@28 $1.07
and sold AHY at $0.97 for a LOSS of $303
only 7 out of 20 entries

That is it for today's journal
 
The initial function code i givetgive you what price you can use to get that 3% extra as asx has rules for increments
0.1c under 10c
0.5c until 2$
1c after

So this part is required and yes, we could compute the number of shares based on $ amount, brokerage and max price allowed based on the function.result
It is doable.
For info noticed a bug in my code to determine nearest asx price, will fix and post tonight.i misunderstood the AB round() function
 
@qldfrog rounding is a bitch & lacks precision, personally I use the "ceil & floor' functions in my strategies for such reasons.

http://www.amibroker.com/guide/afl/ceil.html
http://www.amibroker.com/guide/afl/floor.html

Skate.
My problem was compounded as i was passing such a ceil as an argument, but i would like 0.0439 to be passed as 0.044, 0.0433 as 0.043
0.1234 as 0.125, 0.1278 as 0.13
not rocket sciences and will share the code when fix completed.
But winter is here and a bon fire to clean up the property is priority this afternoon:)
 
AB corrected code:


//return the price as can be used on the asx for sell/buy based on asx increment rules
function GetASXPrice( rawPrice )
{
roundValue = int( rawPrice * 1000 ) * 10;
leftOver = rawPrice * 10000 - roundValue ;//get hundedth of cents value

resP = IIf( rawPrice <= 0.1 , Iif( leftover <= 5 , roundValue, roundValue + 10 ), //0.1c increment
IIf( rawPrice >= 2 , ( Round( rawPrice * 100 ) * 100 ), //1c increment
//otherwise 0.5c increment
IIf( ( rawPrice * 10000 - int( rawPrice * 100 ) * 100 ) < 25, int( rawPrice * 100 ) * 100,
IIf( ( rawPrice * 10000 - int( rawPrice * 100 ) * 100 ) > 75, ( int( rawPrice * 100 ) + 1 ) * 100, int( rawPrice * 100 ) * 100 + 50 ) ) ) );
resP = resP / 10000;
return resP;
}

There is always a decision made as to whether you want to round up, down but at least you are in control
enter a price with as many decimal as required..could be a C*0.97 or C*1.03
and you will get back the ASX precision compliant price
upload_2020-5-20_17-21-53.png
Hope it helps
 
There is always a decision made as to whether you want to round up, down but at least you are in control

@qldfrog for simplicity without looping I use the array "ceil function" & the "floor function" because I'm after rounding up to the max when it comes to a buy offer & the reverse when I place a sell offer in the pre-auction.

An example of rounding
I'll use Woolworths as an example to buy one "chupa chup" lolly with cash.
Normal price $1.03 (buy this with cash & the price rounds down to $1.00)
On "SPECIAL" buy price is $0.97 (buy this with cash & the price rounds up to $1.00)
# The stupidity of rounding - the cash price for one "chupa chup" lolly costs exactly the same at its normal price or the advertised special price which is $1.00

Amibroker logic
BuyOffer = I use the "ceil function" to round prices up to the max
SellOffer = I use the "floor function" to round prices down to the lowest value

Why do I use the "ceil function" to round prices up
Because I want the Buy Offer to add the "full +3% premium" to the last closing price rounded up to 2 decimal places (rounding to 3 decimal places serves no purpose) = ceil function rounds 0.011 up to 0.02
(the standard mathematical rounding function of 0.011 rounds to 0.01)

Why do I use the "floor function" to round prices down
Because I want the Sell Offer to add the "full -3% premium" to the last closing price rounded down to 2 decimal places (rounding to 3 decimal places serves no purpose) = floor function rounds 0.029 down to 0.02 (the standard mathematical rounding functions of 0.029 rounds to 0.03)

Skate.
 
@qldfrog for simplicity without looping I use the array "ceil function" & the "floor function" because I'm after rounding up to the max when it comes to a buy offer & the reverse when I place a sell offer in the pre-auction.

An example of rounding
I'll use Woolworths as an example to buy one "chupa chup" lolly with cash.
Normal price $1.03 (buy this with cash & the price rounds down to $1.00)
On "SPECIAL" buy price is $0.97 (buy this with cash & the price rounds up to $1.00)
# The stupidity of rounding - the cash price for one "chupa chup" lolly costs exactly the same at its normal price or the advertised special price which is $1.00

Amibroker logic
BuyOffer = I use the "ceil function" to round prices up to the max
SellOffer = I use the "floor function" to round prices down to the lowest value

Why do I use the "ceil function" to round prices up
Because I want the Buy Offer to add the "full +3% premium" to the last closing price rounded up to 2 decimal places (rounding to 3 decimal places serves no purpose) = ceil function rounds 0.011 up to 0.02
(the standard mathematical rounding function of 0.011 rounds to 0.01)

Why do I use the "floor function" to round prices down
Because I want the Sell Offer to add the "full -3% premium" to the last closing price rounded down to 2 decimal places (rounding to 3 decimal places serves no purpose) = floor function rounds 0.029 down to 0.02 (the standard mathematical rounding functions of 0.029 rounds to 0.03)

Skate.
I understand the cell and floor but neither take into account the fact that shares below 10 cents can have increments in 0.1 cent
You do not want to go from 4 to 5c, a 20pc jump if you have the choice.
Then for shares between 10c and $2, i think it is useful to use the 0.5c increments
From 10c to 11c is a 10pc jump, whereas to 10.5c is a more reasonable 5c
Obviously is you only buy shares above $2, the problem is not there and not too bad if you have shares above 30c where a 1c increase is the 3pc you look for
So any share price above 30c is not negatively affected by the use of cell/floor.
Share price below: use my function or a custom version
 
I understand the cell and floor but neither take into account the fact that shares below 10 cents can have increments in 0.1 cent

function RoundTickBuy( Price )
{
return
IIf( Price < 0.1, ceil( Price * 1000 ) / 1000,
IIf( Price < 2, ceil( Price * 200 ) / 200,
ceil( Price * 100 ) / 100 ) );
}
function RoundTickSell( Price )
{
return
IIf( Price < 0.1, floor( Price * 1000 ) / 1000,
IIf( Price < 2, floor( Price * 200 ) / 200,
floor( Price * 100 ) / 100 ) );
}
 
function RoundTickBuy( Price )
{
return
IIf( Price < 0.1, ceil( Price * 1000 ) / 1000,
IIf( Price < 2, ceil( Price * 200 ) / 200,
ceil( Price * 100 ) / 100 ) );
}
function RoundTickSell( Price )
{
return
IIf( Price < 0.1, floor( Price * 1000 ) / 1000,
IIf( Price < 2, floor( Price * 200 ) / 200,
floor( Price * 100 ) / 100 ) );
}
more elegant than my code indeed if this works to your preferences
 
Top