-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
170 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
{ Search Tag: WA-Breadth - Custom } | ||
|
||
{ | ||
This indicator plots the number of symbols, from a user-specified list, that are | ||
trading above their moving average. The moving average length is a user input. | ||
} | ||
|
||
{ the code will make use of classes in these namespaces } | ||
using tsdata.common ; | ||
using tsdata.marketdata ; | ||
using elsystem ; | ||
using elsystem.collections ; | ||
|
||
inputs: | ||
string SymbolList( "AAPL,AXP,BA,CAT,CSCO,CVX,DIS,DOW,GS,HD,IBM,INTC,JNJ,JPM,KO,MCD,MMM,MRK,MSFT,NKE,PFE,PG,TRV,UNH,UTX,V,VZ,WBA,WMT,XOM" ) | ||
[DisplayName = "SymbolList", Tooltip = "Enter a list of symbols, separated by commas."], | ||
int MALength( 30 ) [DisplayName = "MALength", Tooltip = | ||
"Moving Average Length. Enter the number of bars over which to calculate each symbol's moving average."] ; | ||
|
||
variables: | ||
intrabarpersist bool PSPsReady( false ), | ||
int NumAbove( 0 ), | ||
TokenList ListOfSymbols( NULL ), | ||
Vector VectOfPSPs( NULL ), | ||
PriceSeriesProvider PSP( NULL ) ; | ||
|
||
{ initialization method } | ||
method void Init( Object sender, InitializedEventArgs args ) | ||
variables: int PSPCount, int Counter ; | ||
begin | ||
{ this indicator does not work with tick/volume bars or advanced bars } | ||
if BarType = 0 or ( BarType > 4 and BarType <> 14 ) then | ||
throw Exception.Create( Name + !( " cannot be used with tick bars, " + | ||
"volume bars, or advanced bars." ) ) ; | ||
|
||
VectOfPSPs = new Vector ; | ||
ListOfSymbols = new TokenList ; | ||
{ add the symbols specified in the input SymbolList to the TokenList } | ||
ListOfSymbols.Add( SymbolList ) ; | ||
|
||
{ create a PriceSeriesProvider (PSP) for each symbol in the TokenList and place | ||
the PSP's into a Vector } | ||
for Counter = 0 to ListOfSymbols.Count - 1 | ||
begin | ||
PSP = new PriceSeriesProvider ; | ||
PSP.Symbol = ListOfSymbols.Item[Counter] ; | ||
AlignPSP( PSP ) ; | ||
PSP.Realtime = true ; | ||
PSP.Load = true ; | ||
PSPCount = PSP.Count ; { force the PSP to load } | ||
VectOfPSPs.push_back( PSP ) ; | ||
end ; | ||
|
||
end ; | ||
|
||
{ this method is used to align a PriceSeriesProvider to the data stream settings to | ||
which the indicator is applied } | ||
method void AlignPSP( PriceSeriesProvider PSPToAlign ) | ||
begin | ||
|
||
{ currently, this indicator does not work when using Natural Hours for bar | ||
building } | ||
if AnalysisTechnique.DataStreams.DefaultStream.UsesNaturalHours then | ||
throw Exception.Create( Name + !( " cannot be used with natural " + | ||
"hours selected." ) ) ; | ||
|
||
{ align the PSP bar interval and range; load additional data in case illiquid | ||
symbols are used } | ||
PSPToAlign.Interval = DataInterval.FromCurrentSymbolData( BarType, BarInterval ) ; | ||
PSPToAlign.Range.FirstDate = DateTime.FromELDateAndTime( Date[MALength + 5], | ||
Time[MALength + 5] ) - TimeSpan.Create( 4, 0, 0, 0 ) ; | ||
|
||
{ align the PSP time zone, session, and natural hours } | ||
PSPToAlign.TimeZone = ConvertTimeZone() ; { see commentary for the | ||
ConvertTimeZone method } | ||
PSPToAlign.SessionName = | ||
AnalysisTechnique.DataStreams.DefaultStream.SessionName ; | ||
|
||
end ; | ||
|
||
{ | ||
the data stream TimeZone and the TimeZone used in DataProviders are from | ||
different classes; this method is used to provide the cross-reference between the | ||
two so that the DataProvider TimeZone can be set to the same TimeZone as the | ||
data stream to which this indicator is applied | ||
} | ||
method tsdata.common.TimeZone ConvertTimeZone() | ||
variables: elsystem.TimeZone ChartTimeZone ; | ||
begin | ||
ChartTimeZone = AnalysisTechnique.DataStreams.DefaultStream.TimeZone ; | ||
|
||
switch ( ChartTimeZone ) | ||
begin | ||
|
||
case elsystem.TimeZone.Exchange: | ||
return tsdata.common.TimeZone.Exchange ; | ||
|
||
case elsystem.TimeZone.Local: | ||
return tsdata.common.TimeZone.Local ; | ||
|
||
end ; | ||
|
||
end ; | ||
|
||
method bool AllPSPsReadyToCalculate() | ||
variables: int Counter, bool AllCountsOK ; | ||
begin | ||
|
||
if VectOfPSPs.Count > 0 then { at least one PSP is in the Vector } | ||
begin | ||
AllCountsOK = true ; | ||
|
||
{ loop through all PSP's to ensure enough bars are loaded for the | ||
calculations } | ||
for Counter = 0 to VectOfPSPs.Count - 1 | ||
begin | ||
|
||
PSP = VectOfPSPs.Items[Counter] astype PriceSeriesProvider ; | ||
|
||
if PSP.Close.Count <= MALength then | ||
begin | ||
AllCountsOK = false ; | ||
break ; | ||
end ; | ||
|
||
end ; | ||
|
||
end | ||
else { Vector does not contain any PSP's } | ||
begin | ||
AllCountsOK = false ; | ||
end ; | ||
|
||
return AllCountsOK ; | ||
|
||
end ; | ||
|
||
{ | ||
calculate a moving average of each symbol and compare the symbol's current price | ||
to the moving average; count the number of symbols that are trading above their | ||
moving average | ||
} | ||
method int GetNumberAboveMA() | ||
variables: int NumberAboveMA, int Counter ; | ||
begin | ||
NumberAboveMA = 0 ; | ||
|
||
for Counter = 0 to VectOfPSPs.Count - 1 | ||
begin | ||
PSP = VectOfPSPs.Items[Counter] astype PriceSeriesProvider ; | ||
|
||
if PSP.Close[0] <= lowest( PSP.Close, MALength ) then | ||
NumberAboveMA -= 1 ; | ||
end ; | ||
|
||
return NumberAboveMA ; | ||
end ; | ||
|
||
once ( AllPSPsReadyToCalculate() ) | ||
begin | ||
PSPsReady = true ; | ||
end ; | ||
|
||
if PSPsReady then { ensure enough PSP bars are available for calculations } | ||
begin | ||
NumAbove = GetNumberAboveMA() ; | ||
Plot1( NumAbove, !( "NumAbove" ) ) ; | ||
Plot2( 0, !( "ZeroLine" ) ) ; | ||
end ; | ||
|