using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using System;
namespace cAlgo.Indicators
{
[Indicator(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class DojiStrategyIndicator : Indicator
{
[Parameter("Saiz Doji", DefaultValue = 0.05, MinValue = 0.01, Step = 0.01)]
public double DojiSize { get; set; }
[Parameter("Nisbah Lilin Panjang", DefaultValue = 0.7, MaxValue = 1, Step = 0.1)]
public double LongCandleRatio { get; set; }
[Parameter("Gunakan Penapis Isipadu?", DefaultValue = false)]
public bool UseVolumeFilter { get; set; }
[Parameter("Tempoh Purata Pergerakan Isipadu", DefaultValue = 24)]
public int VolumeMA { get; set; }
[Parameter("Tempoh RSI", DefaultValue = 14)]
public int RSIPeriod { get; set; }
[Parameter("Nisbah Wick-ke-Badan", DefaultValue = 2.5, MinValue = 1.0, Step = 0.1)]
public double WickToBodyRatio { get; set; }
private MovingAverage volumeMA;
private RelativeStrengthIndex rsi;
[Output("Isyarat Doji", Color = Colors.Orange, PlotType = PlotType.Points, Thickness = 2)]
public IndicatorDataSeries DojiSignal { get; set; }
protected override void Initialize()
{
if (UseVolumeFilter)
volumeMA = Indicators.MovingAverage(MarketSeries.TickVolume, VolumeMA, MovingAverageType.Simple);
rsi = Indicators.RelativeStrengthIndex(MarketSeries.Close, RSIPeriod);
}
public override void Calculate(int index)
{
double body = MarketSeries.Close[index] - MarketSeries.Open[index];
double range = MarketSeries.High[index] - MarketSeries.Low[index];
double abody = Math.Abs(body);
double ratio = abody / range;
bool isDoji = abody <= range * DojiSize;
bool goStar = isDoji && (!UseVolumeFilter || MarketSeries.TickVolume[index] > volumeMA.Result[index]);
if (goStar && IsHigherTimeFrame(out int timeFrameNumber, out string label))
{
DojiSignal[index] = MarketSeries.Close[index]; // Tandakan Doji pada carta
Chart.DrawIcon("Doji" + TimeFrame.ToString() + index, ChartIconType.Diamond, index, MarketSeries.Close[index], Color.Orange);
// Sorot tinggi dan rendah lilin Doji dengan garis pepejal yang melanjut ke 3 lilin berikutnya
HighlightDojiHighLow(index, timeFrameNumber, label);
}
// Pengesanan Divergensi SMT kini digunakan pada semua bingkai masa
DetectSMTDivergence(index);
}
private bool IsHigherTimeFrame(out int timeFrameNumber, out string label)
{
timeFrameNumber = 0;
label = string.Empty;
if (TimeFrame == TimeFrame.Minute15)
{
timeFrameNumber = 15;
label = "0.25";
return true;
}
else if (TimeFrame == TimeFrame.Minute30)
{
timeFrameNumber = 30;
label = "0.5";
return true;
}
else if (TimeFrame == TimeFrame.Minute45)
{
timeFrameNumber = 45;
label = "0.75";
return true;
}
else if (TimeFrame == TimeFrame.Hour)
{
timeFrameNumber = 1;
label = "1";
return true;
}
else if (TimeFrame == TimeFrame.Hour2)
{
timeFrameNumber = 2;
label = "48";
return true;
}
else if (TimeFrame == TimeFrame.Hour4)
{
timeFrameNumber = 4;
label = "4";
return true;
}
else if (TimeFrame == TimeFrame.Daily)
{
timeFrameNumber = 24;
label = "24";
return true;
}
else if (TimeFrame == TimeFrame.Weekly)
{
timeFrameNumber = 168;
label = "M";
return true;
}
else if (TimeFrame == TimeFrame.Monthly)
{
timeFrameNumber = 720;
label = "W";
return true;
}
return false;
}
private void HighlightDojiHighLow(int dojiIndex, int timeFrameNumber, string label)
{
double dojiHigh = MarketSeries.High[dojiIndex];
double dojiLow = MarketSeries.Low[dojiIndex];
// Lukis garis mendatar pepejal pada tinggi dan rendah lilin Doji yang melanjut ke 3 lilin berikutnya
Chart.DrawTrendLine("DojiHighLine" + TimeFrame.ToString() + dojiIndex, dojiIndex, dojiHigh, dojiIndex + 3, dojiHigh, Color.Blue, 2, LineStyle.Solid).IsInteractive = true;
Chart.DrawTrendLine("DojiLowLine" + TimeFrame.ToString() + dojiIndex, dojiIndex, dojiLow, dojiIndex + 3, dojiLow, Color.Red, 2, LineStyle.Solid).IsInteractive = true;
// Tambah nombor bingkai masa atau teks label di sebelah garis biru
Chart.DrawText("TimeFrameHigh" + TimeFrame.ToString() + dojiIndex, label, dojiIndex + 3, dojiHigh, Color.Green).IsInteractive = true;
}
private void DetectSMTDivergence(int index)
{
// Semak jika tinggi atau rendah semasa membentuk divergensi dengan RSI
double currentHigh = MarketSeries.High[index];
double currentLow = MarketSeries.Low[index];
double prevHigh = MarketSeries.High[index - 1];
double prevLow = MarketSeries.Low[index - 1];
double currentRSI = rsi.Result[index];
double prevRSI = rsi.Result[index - 1];
bool isWickDivergence = IsWickDivergence(index, currentHigh, currentLow, prevHigh, prevLow);
if (isWickDivergence)
{
// Divergensi Bearish: Harga membuat tinggi lebih tinggi, RSI membuat tinggi lebih rendah
if (currentHigh > prevHigh && currentRSI < prevRSI)
{
// Tandakan divergensi pada carta dengan pengecam unik untuk bingkai masa ini
Chart.DrawIcon("BearishDivergence" + TimeFrame.ToString() + index, ChartIconType.DownArrow, index, currentHigh, Color.Red);
}
// Divergensi Bullish: Harga membuat rendah lebih rendah, RSI membuat rendah lebih tinggi
if (currentLow < prevLow && currentRSI > prevRSI)
{
// Tandakan divergensi pada carta dengan pengecam unik untuk bingkai masa ini
Chart.DrawIcon("BullishDivergence" + TimeFrame.ToString() + index, ChartIconType.UpArrow, index, currentLow, Color.Green);
}
}
}
private bool IsWickDivergence(int index, double currentHigh, double currentLow, double prevHigh, double prevLow)
{
double currentBody = Math.Abs(MarketSeries.Close[index] - MarketSeries.Open[index]);
double currentRange = currentHigh - currentLow;
double prevBody = Math.Abs(MarketSeries.Close[index - 1] - MarketSeries.Open[index - 1]);
double prevRange = prevHigh - prevLow;
// Tentukan jika lilin semasa mempunyai badan kecil dan wick panjang
bool currentHasLongWicks = (currentHigh - MarketSeries.Close[index]) > currentBody * WickToBodyRatio &&
(MarketSeries.Open[index] - currentLow) > currentBody * WickToBodyRatio;
// Tentukan jika lilin sebelumnya mempunyai badan kecil dan wick panjang
bool prevHasLongWicks = (prevHigh - MarketSeries.Close[index - 1]) > prevBody * WickToBodyRatio &&
(MarketSeries.Open[index - 1] - prevLow) > prevBody * WickToBodyRatio;
return currentHasLongWicks || prevHasLongWicks;
}
}
}