Interesting idea
@Skate. So when this sentiment pre-condition is met, what are the buy conditions...a ranking of the stocks showing the strongest sentiment?
@TraderJimmy I was waiting to see if there was any interest before making additional posts.
Amibroker
Some members don't have Amibroker so I'll post the code & at the same time upload the (afl) for others to backtest & evaluate. The strategy is uploaded for educational purposes only.
FYI
I've used the new Norgate Updater (NDU) format - you will need to change it to suit the format of your data supplier. This strategy has been designed to take advantage of trending markets.
Skate's Daily Sentiment Strategy for ASF Members
Created by: Skate - Last revision 20th August 2020
_SECTION_BEGIN( "# Skate's Daily Sentiment Strategy Exploration" );
//=================================================================================
//1. The "SetOptions" are management options & they are a feature of Amibroker
//=================================================================================
TradingFunds = Param( "Trading Funds - $", 5000, 1000, 10000000, 1000 ); // User-definable parameter, accessible via Exploration parameters - changes are reflected immediately. (Default $5k bets) - INSERT any amount
SetOption( "InitialEquity", 100000 ); // $100k Inital Equity (allows for 20 X $5k bets)
SetOption( "PriceBoundChecking", 1 ); // True: Adjust prices so that they fall within the High-Low range
SetOption( "CommissionMode", 2 ); // Use $ amount
SetOption( "CommissionAmount", 19.95 ); // CommSec commission rate
SetOption( "UsePrevBarEquityForPosSizing", 1 ); // True: Use previous bar closing equity to perform position sizing
SetOption( "AllowSameBarExit", False ); // False: Trade is exited & we move to next bar ignoring other signals
RestorePriceArrays( True ); // Restores original price & volume arrays after the call to SetForeign.
SetTradeDelays( 1, 1, 1, 1 ); // Trade delays, the delay is required for backtesting
//=================================================================================
//2. The "Buy Filter" - decides when we will trade & also our trailing stop levels
//=================================================================================
Index = Foreign("$XAO.au","C",True); // I've used the new Norgate Updater (NDU) format -
IMPORTANT: change if the format is different to your data supplier
MAfilter = MA( Index, 20 ); // 20 Day lookback period
IndexBuyFilter = Index > MAfilter; // Index Filter = ON: When the close is greater than the 20 Day simple moving average the Index Filter is ON [trailing stop set to 20%] + [buy + sell signals generated]
IndexSellFilter = Index < MAfilter; // Index Filter = OFF: When the close is less than the 20 Day simple moving average the Index Filter is OFF [shortens trailing stop to 10%] + [only sell signals generated]
//=================================================================================
//3. Add all our other filters
//=================================================================================
Liq = C * V; // Liquidity Filter
CV = 500000; // Volume Filter
Liqfactor = Liq > CV; // Liquidity Filter
ROCFilter = ROC( C, 20 ) > 30; // Rate Of Change (ROC) Momentum filter
ROCParameter = Param( "ROC Parameter", 8, 0, 52, 1 ); // 8 Day Rate of Change period
MOMFilter = ( ROC( C, 10 ) >= ROCParameter ); // Momentum filter - the closing price of the last 10 Days is greater than the last 8 Days
NoStrength = Close < MA( Close, 12 ); // If the closing price is less then the Simple Moving Average of the last 12 Days it's considered there is no strength in the move
//=================================================================================
//4. Add a sentiment buy condition
//=================================================================================
MAp = Optimize( "MAp", 14, 5, 20, 1 ); // The optimised EMA period (14) is used for the Daily Sentiment calculation.
MApV = Optimize( "MApV", 14, 5, 20, 1 ); // The optimised MA period (14) used when calculating the MA of the Daily Sentiment.
VLow = Optimize( "VLow", 40, 10, 90, 10 ); // The optimised "Low level" is set at (-40) meaning the value is negative
VHigh = Optimize( "VHigh", 40, 10, 90, 10 ); // The optimised "High level" is set at (+40) meaning the value is positive
function DSC( MAp )
{
R = sign( C - Ref( C, -1 ) ) * V;
VP = EMA( R, MAp );
TV = EMA( V, MAp );
return Nz( 100 * VP / TV );
}
DS = Cross( DSC( MAp ), -VLow ); // Buy if the (Daily Sentiment) crosses -40 from below (VLow)
NoUpTrend = Cross( VHigh, DSC( MAp ) ); // Sell if the (Daily Sentiment) crosses +40 from above (VHigh)
//=================================================================================
// Open new long positions only when the Sentiment is positive
//=================================================================================
Cond1 = C > Ref( HHV( C, DS ), -1 ); // Buy when the closing price of the (Daily Sentiment) crosses -40 (VLow) from below
Cond2 = IndexBuyFilter; // Buy ONLY when the Buy Filter is ON
cond3 = C >= 0.05; // Buy only if the closing price is greater $0.05 (5 cents)
cond4 = C <= 10; // Buy only if the closing price is less than $10.00
cond5 = liqfactor; // Buy only when the Liquidity filter is TRUE
cond6 = ROCFilter AND MOMFilter; // Buy only when the Rate of Change filter & Momentum filter is TRUE
Buy = cond1
AND cond2
AND cond3
AND cond4
AND cond5
AND cond6;
//=================================================================================
//5. Add a sell condition
//=================================================================================
Sell = C < MA( C, 50 ) AND NoStrength AND NoUpTrend; // Sell when the close is less than the moving average of the last 50 Days with the closing price is less than the Simple Moving Average of the last 12 Days or Sell when there is NoUpTrend as the trend has ended
//=================================================================================
//6. Add a two-stage trailing stop
//=================================================================================
ts1 = 20;
ts2 = 10;
ts = IIf( IndexBuyFilter , ts1 , ts2 );
ApplyStop( stopTypeTrailing , stopModePercent , ts , exitatstop = 2 ); // Apply Stop = [ts] Trailing Stop [exitatstop = 2] means check High-Low prices but exit NEXT BAR on regular trade price.
//=================================================================================
//7. Remove excessive signals & add "Position Sizing"
//=================================================================================
BuyPrice = Open; // Buy the next day at open
SellPrice = Open; // Sell the next day at open
Buy = ExRem( Buy, Sell ); // Removes additional buy signals
Sell = ExRem( Sell, Buy ); // Removes additional sell signals
//=================================================================================
// Position Sizing
//=================================================================================
PosQty = 20; // Position Quantity = Maximum 20 positions
PositionSize = -100 / posqty; // 100% of the equity divided by the Position Size
SetOption( "MaxOpenPositions", PosQty ); // Maximum number of open position
//=================================================================================
//8. Add "Filters for the Exploration Analysis"
//=================================================================================
Filter = Buy OR Sell; // Buy & Sell Filters
//=================================================================================
//9. Add Buy & Sell coding for use in trading the pre-auction
//=================================================================================
BuyOffered = Close * 1.03; // +3% Buy premium over the last closing price
BuyOffer = ceil( BuyOffered * 100 ) / 100; // The amount is rounded up no matter the price (ceil function used)
SellOffered = Close * 0.97; // -3% Sell premium below the last closing price
SellOffer = floor( SellOffered * 100 ) / 100; // The amount is rounded down no matter the price (floor function used)
//=================================================================================
//10. Add the Exploration code
//=================================================================================
ToBuyPosSize = floor( TradingFunds / BuyOffer ); // Trading Funds divided by buy offer of (+3%) buy premium over the last closing price
ToBuyPosCost = BuyOffer * ToBuyPosSize; // The cost of buying the amount of share
PositionScorer = 100 - Close; // Lowest priced security at BuySetup trigger is taken first
PositionScore = Ref( PositionScorer, -1 ); // Previous bar (-1 bar)
//=================================================================================
//11. Add columns to report & sort the Exploration Analysis results
//=================================================================================
AddColumn( IIf( Buy, ToBuyPosSize, Null ), "# shares", 1, colorWhite, colorDarkGreen, 90 ); // Exploration Analysis - this column displays quantity of shares to buy
AddColumn( IIf( Buy, BuyOffer, Null ), "$ Buy Offer", 1.2, colorWhite, colorDarkGreen, 110 ); // Exploration Analysis - this column displays pre-auction buy offer price (+3% premium added to the last closing price)
AddColumn( IIf( Buy, ToBuyPosCost, Null ), "$ Cost", 1.2, colorWhite, colorDarkGreen, 80 ); // Exploration Analysis - this column displays the total ($) you will pay for the qty of shares at the +3% primum
AddColumn( IIf( Sell, SellOffer, Null ), "$ Sell Offer", 1.2, colorWhite, colorRed, 110 ); // Exploration Analysis - this column displays pre-auction sell offer price (-3% discount to the last closing price)
SetSortColumns( -2, -3, -4, -5, -6, 1 ); // Sort the columns in correct order
_SECTION_END();
//=================================================================================
//12. Add code to the chart & plots the signals. Also adding a Buy Ribbon
//=================================================================================
_SECTION_BEGIN( "Price" );
SetChartOptions( 0, chartShowArrows | chartShowDates );
_N( Title = StrFormat( "{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) Vol " + WriteVal( V, 1.0 ) + " {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ) ); // Chart settings
Plot( C, "Close", ParamColor( "Color", colorBlack ),
ParamStyle( "Style", styleNoTitle | styleBar, maskAll ) ); // User-definable parameter, accessible via Chart parameters - changes are reflected immediatelly. (Bar Chart Default)
PlotShapes( Buy*shapehollowUpArrow, colorWhite, 0, Low, -20 ); // Displays Buy up arrow on the signal bar
PlotShapes( ( Sell > 0 ) * shapeDownArrow, Coloryellow, 0, High, -40 ); // Displays Sell down arrow on the signal bar
PlotShapes( Ref( Buy, -1 ) * shapeHollowSquare, colorWhite, 0, O, 0, 0 ); // Displays a white square on the buy bar
PlotShapes( Ref( Sell, -1 ) * shapeHollowCircle, colorYellow, 0, O, 0, 0 ); // Displays a yellow circle on the sell bar
BuyFilter = IIf( IndexBuyFilter, True, False ); // If Buy Filter is TRUE (ON), or If Buy Filter is FALSE (OFF),
RibbonColor = IIf( Buyfilter, colorGreen, colorRed ); // If Buy Filter is TRUE (ON) the ribbon is GREEN, or If Buy Filter is FALSE (OFF) the ribbon is Red
Plot( 1, "", RibbonColor, styleArea | styleOwnScale | styleNoLabel, -0.0001, 190 ); // Plots the Buy Filter Ribbon [green = ON] [Red = OFF]
for( i = 1; i < BarCount; i++ )
{
if( Buy[i - 1] ) PlotText( "Buy\n@ " + O, i, L * 0.9, colorWhite ); // Displays white buy price (opening price) under the white box (buy bar)
if( sell[i - 1] ) PlotText( "Sell\n@ " + o[ i ], i, H[ i ] * 1.1, colorYellow ); // Displays yellow sell price (opening price) above the yellow circle (sell bar)
}
_SECTION_END();
Skate.