Initial commit
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30011.22
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HmaMitigationCount", "HmaMitigationCount\HmaMitigationCount.csproj", "{a7f42ba9-479c-418c-83b4-228416c67510}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{a7f42ba9-479c-418c-83b4-228416c67510}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{a7f42ba9-479c-418c-83b4-228416c67510}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{a7f42ba9-479c-418c-83b4-228416c67510}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{a7f42ba9-479c-418c-83b4-228416c67510}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,162 @@
|
||||
using cAlgo.API;
|
||||
using cAlgo.API.Indicators;
|
||||
using cAlgo.API.Internals;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace cAlgo.Indicators
|
||||
{
|
||||
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
|
||||
public class HmaMitigationCount : Indicator
|
||||
{
|
||||
[Parameter("HMA Period", DefaultValue = 20, MinValue = 2)]
|
||||
public int HmaPeriod { get; set; }
|
||||
|
||||
[Parameter("Session Close Time (UTC)", DefaultValue = "17:30")]
|
||||
public TimeSpan SessionCloseTimeUtc { get; set; }
|
||||
|
||||
[Output("HMA", LineColor = "Orange")]
|
||||
public IndicatorDataSeries HmaOutput { get; set; }
|
||||
|
||||
private HullMovingAverage _hma;
|
||||
private Stack<double> _peakStack;
|
||||
private Stack<double> _troughStack;
|
||||
private int lblCnt = 0;
|
||||
private int mitigatedPeaks = 0;
|
||||
private int mitigatedTroughs = 0;
|
||||
private int dir = 0;
|
||||
|
||||
private DateTime _currentSessionEndTimeUtc = DateTime.MinValue;
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
_hma = Indicators.HullMovingAverage(Bars.ClosePrices, HmaPeriod);
|
||||
_peakStack = new Stack<double>();
|
||||
_troughStack = new Stack<double>();
|
||||
}
|
||||
|
||||
public override void Calculate(int index)
|
||||
{
|
||||
HmaOutput[index] = _hma.Result[index];
|
||||
DateTime barOpenTime = Bars.OpenTimes[index]; // This is UTC
|
||||
|
||||
// --- Session Initialization (run once) ---
|
||||
if (_currentSessionEndTimeUtc == DateTime.MinValue)
|
||||
{
|
||||
// Find the session close time for the *current* bar's day
|
||||
DateTime sessionCloseToday = barOpenTime.Date.Add(SessionCloseTimeUtc);
|
||||
|
||||
// If the bar is already *after* today's close, the session ends *tomorrow*
|
||||
if (barOpenTime >= sessionCloseToday)
|
||||
{
|
||||
_currentSessionEndTimeUtc = sessionCloseToday.AddDays(1);
|
||||
}
|
||||
// If the bar is *before* today's close, the session ends *today*
|
||||
else
|
||||
{
|
||||
_currentSessionEndTimeUtc = sessionCloseToday;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Session Check ---
|
||||
// Check if the current bar has crossed the session boundary
|
||||
if (barOpenTime >= _currentSessionEndTimeUtc)
|
||||
{
|
||||
// New session starts, clear stacks
|
||||
_peakStack.Clear();
|
||||
_troughStack.Clear();
|
||||
//Chart.RemoveAllObjects(); // Optional: Clear old session text
|
||||
|
||||
// Set the *next* session end time, looping in case of market gaps (weekends)
|
||||
while (barOpenTime >= _currentSessionEndTimeUtc)
|
||||
{
|
||||
_currentSessionEndTimeUtc = _currentSessionEndTimeUtc.AddDays(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop logic from running on the forming bar
|
||||
if (IsLastBar)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// We need at least 3 bars to identify a peak/trough at index - 1
|
||||
if (index < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 1. Identify new peaks/troughs at index - 1 AND check mitigation ---
|
||||
// All HMA values are now based on closed bars (index, index-1, index-2).
|
||||
double prevHma = _hma.Result[index - 1];
|
||||
double prevHma2 = _hma.Result[index - 2];
|
||||
double currentHma = _hma.Result[index];
|
||||
|
||||
// A peak at index-1
|
||||
bool isPeak = (prevHma > prevHma2) && (prevHma > currentHma);
|
||||
// A trough at index-1
|
||||
bool isTrough = (prevHma < prevHma2) && (prevHma < currentHma);
|
||||
|
||||
if (isPeak)
|
||||
{
|
||||
// New Peak: Check if it mitigates any *previous Peaks*
|
||||
if( dir < 0 )
|
||||
{
|
||||
mitigatedPeaks = 0;
|
||||
lblCnt++;
|
||||
}
|
||||
|
||||
// A new peak (prevHma) mitigates old peaks that are *lower*
|
||||
while (_peakStack.Count > 0 && prevHma >= _peakStack.Peek())
|
||||
{
|
||||
_peakStack.Pop(); // Pop the mitigated (lower) peak
|
||||
mitigatedPeaks++;
|
||||
}
|
||||
|
||||
if (mitigatedPeaks > 0)
|
||||
{
|
||||
// Draw mitigation count above the peak bar
|
||||
// The remaining count is the peaks *higher* than the new one
|
||||
string label = $"Mit: {mitigatedPeaks} / Rem: {_peakStack.Count}";
|
||||
double yPos = Bars.HighPrices[index - 1] + Symbol.PipSize * 5;
|
||||
Chart.DrawText($"peak_mit_{lblCnt}", label, index - 1, yPos, Color.Red);
|
||||
dir = 1;
|
||||
}
|
||||
|
||||
// Add the new peak to its own stack
|
||||
_peakStack.Push(prevHma);
|
||||
}
|
||||
|
||||
if (isTrough)
|
||||
{
|
||||
// New Trough: Check if it mitigates any *previous Troughs*
|
||||
if( dir > 0 )
|
||||
{
|
||||
mitigatedTroughs = 0;
|
||||
lblCnt++;
|
||||
}
|
||||
|
||||
// A new trough (prevHma) mitigates old troughs that are *higher*
|
||||
while (_troughStack.Count > 0 && prevHma <= _troughStack.Peek())
|
||||
{
|
||||
_troughStack.Pop(); // Pop the mitigated (higher) trough
|
||||
mitigatedTroughs++;
|
||||
}
|
||||
|
||||
if (mitigatedTroughs > 0)
|
||||
{
|
||||
// Draw mitigation count below the trough bar
|
||||
// The remaining count is the troughs *lower* than the new one
|
||||
string label = $"Mit: {mitigatedTroughs} / Rem: {_troughStack.Count}";
|
||||
double yPos = Bars.LowPrices[index - 1] - Symbol.PipSize * 5;
|
||||
Chart.DrawText($"trough_mit_{lblCnt}", label, index - 1, yPos, Color.Lime);
|
||||
dir = -1;
|
||||
}
|
||||
|
||||
// Add the new trough to its own stack
|
||||
_troughStack.Push(prevHma);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="cTrader.Automate" Version="*" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user