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}") = "ImbalanceAlert", "ImbalanceAlert\ImbalanceAlert.csproj", "{c36a0d9f-f01d-43c6-8718-c23e761197a5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{c36a0d9f-f01d-43c6-8718-c23e761197a5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{c36a0d9f-f01d-43c6-8718-c23e761197a5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{c36a0d9f-f01d-43c6-8718-c23e761197a5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{c36a0d9f-f01d-43c6-8718-c23e761197a5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,170 @@
|
||||
using System;
|
||||
using cAlgo.API;
|
||||
using cAlgo.API.Internals;
|
||||
|
||||
namespace cAlgo
|
||||
{
|
||||
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
|
||||
public class ImbalanceAlert : Indicator
|
||||
{
|
||||
#region Parameters
|
||||
|
||||
// Alert Settings
|
||||
[Parameter("Send Email", DefaultValue = true, Group = "Alert Settings")]
|
||||
public bool SendEmail { get; set; }
|
||||
|
||||
[Parameter("Sender Email", DefaultValue = "junk001@mycelium.de", Group = "Alert Settings")]
|
||||
public string SenderEmail { get; set; }
|
||||
|
||||
[Parameter("Recipient Email", DefaultValue = "junk001@mycelium.de", Group = "Alert Settings")]
|
||||
public string RecipientEmail { get; set; }
|
||||
|
||||
[Parameter("Play Sound", DefaultValue = true, Group = "Alert Settings")]
|
||||
public bool PlaySound { get; set; }
|
||||
|
||||
[Parameter("Sound File Path", DefaultValue = "C:\\Windows\\Media\\Alarm07.wav", Group = "Alert Settings")]
|
||||
public string SoundFilePath { get; set; }
|
||||
|
||||
// Filters
|
||||
[Parameter("Min Gap Size (Pips)", DefaultValue = 1.0, Group = "Filters")]
|
||||
public double MinGapSizePips { get; set; }
|
||||
|
||||
// Visuals
|
||||
[Parameter("Draw Boxes", DefaultValue = true, Group = "Visuals")]
|
||||
public bool DrawBoxes { get; set; }
|
||||
|
||||
[Parameter("Bullish Color", DefaultValue = "Green", Group = "Visuals")]
|
||||
public string BullishColorName { get; set; }
|
||||
|
||||
[Parameter("Bearish Color", DefaultValue = "Red", Group = "Visuals")]
|
||||
public string BearishColorName { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
private int _lastAlertBarIndex = -1;
|
||||
private Color _bullColor;
|
||||
private Color _bearColor;
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
// 50% Transparency (Alpha 127 out of 255)
|
||||
_bullColor = Color.FromArgb(127, Color.FromName(BullishColorName));
|
||||
_bearColor = Color.FromArgb(127, Color.FromName(BearishColorName));
|
||||
}
|
||||
|
||||
public override void Calculate(int index)
|
||||
{
|
||||
// Need at least 3 completed bars (index-3 to index-1)
|
||||
if (index < 3) return;
|
||||
|
||||
int cIndex = index - 1; // The closed bar confirming the gap
|
||||
int aIndex = index - 3; // The origin bar
|
||||
|
||||
double highA = Bars.HighPrices[aIndex];
|
||||
double lowA = Bars.LowPrices[aIndex];
|
||||
|
||||
double highC = Bars.HighPrices[cIndex];
|
||||
double lowC = Bars.LowPrices[cIndex];
|
||||
|
||||
// Check Bullish FVG (Undervalued)
|
||||
// Gap is between High of A and Low of C
|
||||
if (lowC > highA)
|
||||
{
|
||||
// Bottom: HighA, Top: LowC
|
||||
ProcessGap(true, aIndex, cIndex, highA, lowC, index);
|
||||
}
|
||||
// Check Bearish FVG (Overvalued)
|
||||
// Gap is between Low of A and High of C
|
||||
else if (highC < lowA)
|
||||
{
|
||||
// Bottom: HighC, Top: LowA (Bugfix: Parameter order swapped)
|
||||
ProcessGap(false, aIndex, cIndex, highC, lowA, index);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessGap(bool isBullish, int startBarIdx, int endBarIdx, double bottomPrice, double topPrice, int currentIndex)
|
||||
{
|
||||
double gapSize = topPrice - bottomPrice;
|
||||
|
||||
// Check against min size
|
||||
if (gapSize < MinGapSizePips * Symbol.PipSize) return;
|
||||
|
||||
// Visualization
|
||||
if (DrawBoxes)
|
||||
{
|
||||
string objName = $"FVG_{startBarIdx}";
|
||||
var color = isBullish ? _bullColor : _bearColor;
|
||||
|
||||
// Draw rectangle
|
||||
var rect = Chart.DrawRectangle(objName, startBarIdx, bottomPrice, endBarIdx, topPrice, color, 1, LineStyle.Solid);
|
||||
rect.IsFilled = true;
|
||||
}
|
||||
|
||||
// Alert Logic
|
||||
if (IsLastBar && RunningMode == RunningMode.RealTime)
|
||||
{
|
||||
if (_lastAlertBarIndex != currentIndex)
|
||||
{
|
||||
TriggerAlerts(isBullish, topPrice, bottomPrice);
|
||||
_lastAlertBarIndex = currentIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerAlerts(bool isBullish, double top, double bottom)
|
||||
{
|
||||
string type = isBullish ? "BULLISH" : "BEARISH";
|
||||
string message = $"{Symbol.Name} ({TimeFrame}): {type} Imbalance Detected. Range: {bottom} - {top}";
|
||||
|
||||
// 1. Sound Alert
|
||||
if (PlaySound)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(SoundFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
Notifications.PlaySound(SoundFilePath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Notifications.PlaySound(SoundType.Doorbell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Email Alert
|
||||
if (SendEmail)
|
||||
{
|
||||
SendAlertEmail(type, top, bottom);
|
||||
}
|
||||
|
||||
Print(message);
|
||||
}
|
||||
|
||||
private void SendAlertEmail(string type, double top, double bottom)
|
||||
{
|
||||
try
|
||||
{
|
||||
string subject = $"{Symbol.Name} ({TimeFrame}): {type} Imbalance Detected";
|
||||
string body = $@"
|
||||
<h1>Imbalance Manifested</h1>
|
||||
<p><strong>Symbol:</strong> {Symbol.Name}</p>
|
||||
<p><strong>Timeframe:</strong> {TimeFrame}</p>
|
||||
<p><strong>Direction:</strong> {type}</p>
|
||||
<p><strong>Gap Range:</strong> {bottom} - {top}</p>
|
||||
<p><strong>Time:</strong> {Server.Time.ToUniversalTime()} UTC</p>
|
||||
";
|
||||
|
||||
Notifications.SendEmail(SenderEmail, RecipientEmail, subject, body);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Print($"Failed to send email: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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