// Bell Curve: Close Price vs 200-Day MA Distribution
// Plots histogram + Gaussian fit for (Close / MA200) ratios
// Parameters
MA_Period = 200;
Num_Bins = 50; // Adjust for smoother histogram
Min_Ratio = 0.5; // X-axis range
Max_Ratio = 1.5;
Bin_Width = (Max_Ratio - Min_Ratio) / Num_Bins;
// Compute ratios (only where MA is valid)
MA200 = MA(Close, MA_Period);
Ratio = IIf(MA200 > 0, Close / MA200, Null); // Avoid div by zero
Valid_Ratio = IIf(BarIndex() >= MA_Period - 1 AND !IsNull(Ratio), Ratio, Null);
// Collect valid ratios into an array
Num_Bars = BarCount;
Ratio_Array = Null;
for(i = MA_Period - 1; i < Num_Bars; i++) {
if(!IsNull(Valid_Ratio[i])) {
Ratio_Array[i] = Valid_Ratio[i];
}
}
// Compute histogram
Hist = 0;
for(i = MA_Period - 1; i < Num_Bars; i++) {
if(!IsNull(Ratio_Array[i])) {
bin_idx = Floor((Ratio_Array[i] - Min_Ratio) / Bin_Width);
if(bin_idx >= 0 AND bin_idx < Num_Bins) {
Hist[bin_idx] = Nz(Hist[bin_idx]) + 1;
}
}
}
// Compute Gaussian parameters (mean and std dev)
Sum_R = 0; Count = 0; Sum_Sq = 0;
for(i = MA_Period - 1; i < Num_Bars; i++) {
r = Ratio_Array[i];
if(!IsNull(r)) {
Sum_R += r;
Sum_Sq += r * r;
Count++;
}
}
Mean = IIf(Count > 0, Sum_R / Count, 0);
Variance = IIf(Count > 0, (Sum_Sq / Count) - (Mean * Mean), 0);
StdDev = IIf(Count > 0, sqrt(Max(Variance, 0)), 0);
// Normalize histogram
Max_Hist = 0;
for(i = 0; i < Num_Bins; i++) {
if(Nz(Hist[i]) > Max_Hist) Max_Hist = Nz(Hist[i]);
}
Norm_Hist = IIf(Max_Hist > 0, Hist / Max_Hist, 0);
// Gaussian curve points
GraphX = 0; GraphY = 0; Max_GraphY = 0;
for(i = 0; i < Num_Bins; i++) {
x = Min_Ratio + (i + 0.5) * Bin_Width;
GraphX[i] = x;
if(StdDev > 0.0001) { // Added small threshold to prevent div by zero
GraphY[i] = exp(-((x - Mean) / (2 * StdDev * StdDev)) ^ 2) / (StdDev * sqrt(2 * 3.14159));
} else {
GraphY[i] = 0;
}
if(GraphY[i] > Max_GraphY) Max_GraphY = GraphY[i];
}
GraphY = IIf(Max_GraphY > 0, GraphY * Max_Hist / Max_GraphY, 0);
// Plot main chart
Plot(Close, "Close", colorBlack, styleCandle);
Plot(MA200, "200 DMA", colorBlue, styleLine);
// Custom pane for bell curve
_SECTION_BEGIN("Bell Curve");
SetChartOptions(0, chartShowArrows | chartShowDates);
SetChartBkColor(colorWhite);
// Gfx setup
Pane_Width = Status("pxwidth") / 2; // Dynamic scaling
Pane_Height = 100;
GfxSetOverlayMode(1);
GfxSelectFont("Arial", 10);
GfxSetBkMode(1);
// Draw axes
GfxSelectPen(colorRGB(128,128,128), 1);
GfxMoveTo(10, Pane_Height - 10); GfxLineTo(Pane_Width - 10, Pane_Height - 10); // X axis
GfxMoveTo(10, 10); GfxLineTo(10, Pane_Height - 10); // Y axis
// Labels
GfxTextOut("Ratio (Close / 200DMA)", Pane_Width / 2 - 50, Pane_Height - 5);
GfxTextOut("Frequency", 5, Pane_Height / 2);
// Draw histogram bars
GfxSelectSolidBrush(colorRGB(135,206,250)); // Light blue
for(i = 0; i < Num_Bins; i++) {
bar_height = (Pane_Height - 20) * Nz(Norm_Hist[i]);
bar_x = 10 + (i * ((Pane_Width - 20) / Num_Bins));
GfxRectangle(bar_x, Pane_Height - 10 - bar_height, bar_x + ((Pane_Width - 20) / Num_Bins) - 2, Pane_Height - 10);
}
// Draw Gaussian curve
GfxSelectPen(colorRed, 2);
first_point = True;
for(i = 0; i < Num_Bins; i++) {
curve_y = 10 + (Pane_Height - 20) * Nz(GraphY[i] / Max_Hist);
curve_x = 10 + (i * ((Pane_Width - 20) / Num_Bins));
if(first_point) {
GfxMoveTo(curve_x, Pane_Height - 10 - curve_y);
first_point = False;
} else {
GfxLineTo(curve_x, Pane_Height - 10 - curve_y);
}
}
// Mean line
if(Count > 0) {
GfxSelectPen(colorGreen, 1, 2); // Dashed
GfxSetCoordsMode(1);
x_scaled = 10 + ((Mean - Min_Ratio) / (Max_Ratio - Min_Ratio)) * (Pane_Width - 20);
GfxMoveTo(x_scaled, 0);
GfxLineTo(x_scaled, Pane_Height);
}
// Text annotations
GfxTextOut("Mean: " + NumToStr(Mean, 1.3), 10, 5);
GfxTextOut("StdDev: " + NumToStr(StdDev, 1.3), 10, 20);
GfxTextOut("Data Points: " + NumToStr(Count, 1.0), 10, 35);
_SECTION_END();
// Title
Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} O=%.2f H=%.2f L=%.2f C=%.2f (%.1f%%) " +
"Ratio Mean=%.3f Std=%.3f",
O, H, L, C, SelectedValue(ROC(Close, 1)), Mean, StdDev);