Skip to content

Instantly share code, notes, and snippets.

@joemaller
Last active June 24, 2025 02:54
Show Gist options
  • Save joemaller/c8dc01bbbd7411021e94e4f017a6de59 to your computer and use it in GitHub Desktop.
Save joemaller/c8dc01bbbd7411021e94e4f017a6de59 to your computer and use it in GitHub Desktop.
Five Horseman Indicator
# Display in a lower subgraph
declare lower;
# Top-Five QQQ components with rankings from Invesco
input stock1 = "MSFT";
input weight1 = 8.85;
input stock2 = "NVDA";
input weight2 = 8.754;
input stock3 = "AAPL";
input weight3 = 7.488;
input stock4 = "AMZN";
input weight4 = 5.552;
input stock5 = "GOOGL";
input weight5 = 4.703;
input length = 8;
# Five Horsemen Weight
def fhw = weight1 + weight2 + weight3 + weight4 + weight5;
def stock1Close = close(stock1);
def stock1Change = (stock1Close - stock1Close[length]) / stock1Close[length] * 100;
def stock1Avg = MovingAverage(AverageType.EXPONENTIAL, stock1Change, length);
;
def stock2Close = close(stock2);
def stock2Change = (stock2Close - stock2Close[length]) / stock2Close[length] * 100;
def stock2Avg = MovingAverage(AverageType.EXPONENTIAL, stock2Change, length);
def stock3Close = close(stock3);
def stock3Change = (stock3Close - stock3Close[length]) / stock3Close[length] * 100;
def stock3Avg = MovingAverage(AverageType.EXPONENTIAL, stock3Change, length);
def stock4Close = close(stock4);
def stock4Change = (stock4Close - stock4Close[length]) / stock4Close[length] * 100;
def stock4Avg = MovingAverage(AverageType.EXPONENTIAL, stock4Change, length);
def stock5Close = close(stock5);
def stock5Change = (stock5Close - stock5Close[length]) / stock5Close[length] * 100;
def stock5Avg = MovingAverage(AverageType.EXPONENTIAL, stock5Change, length);
def fhAverage = ( stock1Avg * weight1 + stock2Avg * weight2 + stock3Avg * weight3 + stock4Avg * weight4 + stock5Avg * weight5) / fhw;
def qqqClose = close(stock1);
def qqqChange = (qqqClose - qqqClose[length]) / qqqClose[length] * 100;
def qqqAvg = MovingAverage(AverageType.EXPONENTIAL, qqqChange, length);
def histogram = fhAverage - qqqAvg;
plot zeroLine = 0;
zeroLine.SetDefaultColor(Color.GRAY);
plot qqqLine = qqqAvg;
plot fhLine = fhAverage;
qqqLine.SetDefaultColor(Color.DARK_GREEN);
fhLine.SetDefaultColor(Color.VIOLET);
plot Diff = histogram;
Diff.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
Diff.DefineColor("Up", CreateColor(0, 80, 0));
Diff.DefineColor("Down", CreateColor(128, 0, 0));
Diff.AssignValueColor(
if histogram > 0 then
Diff.Color("Up")
else
Diff.Color("Down")
);
def crossUp = fhLine crosses above qqqLine;
def crossDown = fhLine crosses below qqqLine;
plot upArrow = if crossUp then fhLine - 0.1 else Double.NaN;
upArrow.setPaintingStrategy(PaintingStrategy.ARROW_UP);
upArrow.setDefaultColor(CreateColor(180, 255, 255));
plot downArrow = if crossDown then fhLine + 0.1 else Double.NaN;
downArrow.setPaintingStrategy(PaintingStrategy.ARROW_DOWN);
downArrow.setDefaultColor(CreateColor(255, 255, 180));
# Display in a lower subgraph
declare lower;
# Top-Five QQQ components with rankings from Invesco
input stock1 = "MSFT";
input weight1 = 8.85;
input stock2 = "NVDA";
input weight2 = 8.754;
input stock3 = "AAPL";
input weight3 = 7.488;
input stock4 = "AMZN";
input weight4 = 5.552;
input stock5 = "GOOGL";
input weight5 = 4.703;
input qqq = "QQQ";
input rsiLength = 20;
# Five Horsemen Weight
def fhw = weight1 + weight2 + weight3 + weight4 + weight5;
def rsi1 = RSI(price = close(symbol = stock1), length = rsiLength, average_type= averageType.WILDERS);
def rsi2 = RSI(price = close(symbol = stock2), length = rsiLength, average_type= averageType.WILDERS);
def rsi3 = RSI(price = close(symbol = stock3), length = rsiLength, average_type= averageType.WILDERS);
def rsi4 = RSI(price = close(symbol = stock4), length = rsiLength, average_type= averageType.WILDERS);
def rsi5 = RSI(price = close(symbol = stock5), length = rsiLength, average_type= averageType.WILDERS);
def fhRSI = ( rsi1 * weight1 + rsi2 * weight2 + rsi3 * weight3 + rsi4 * weight4 + rsi5 * weight5) / fhw;
def qqqRSI = RSI(price = close(symbol = "QQQ"), length = rsiLength, average_type= averageType.WILDERS);
plot qqqLine =qqqRSI;
qqqLine.SetDefaultColor(Color.VIOLET);
qqqLine.SetLineWeight(1);
plot fhLine = fhRSI;
fhLine.SetDefaultColor(Color.DARK_GREEN);
fhLine.SetLineWeight(1);
def crossUp = qqqLine crosses above fhLine;
def crossDown = qqqLine crosses below fhLine;
plot upArrow = if crossUp then fhLine - 5 else Double.NaN;
upArrow.setPaintingStrategy(PaintingStrategy.ARROW_UP);
upArrow.setDefaultColor(CreateColor(180, 255, 180));
plot downArrow = if crossDown then fhLine + 5 else Double.NaN;
downArrow.setPaintingStrategy(PaintingStrategy.ARROW_DOWN);
downArrow.setDefaultColor(CreateColor(255, 180, 180));
@joemaller
Copy link
Author

joemaller commented Jun 9, 2025

@joemaller
Copy link
Author

joemaller commented Jun 9, 2025

Todo:

  • Add per-symbol weights from Invesco (excel)
  • MACD, but instead of moving averages, show single averages for QQQ vs. 5H with a histogram
  • Add Crossover Indicator arrows
  • Make the colors make sense (consistency)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment