Hello, here is the first BETA release from Convert. Could you send me a screenshot of how it looks in ThinkorSwim?
#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
using NinjaTrader.NinjaScript.Indicators;
#endregion
namespace NinjaTrader.NinjaScript.Indicators
{
public class WolfeWaveNT8_Opt : Indicator
{
[Range(2, 50), NinjaScriptProperty]
public int WaveLength { get; set; } = 13;
[NinjaScriptProperty]
public bool LabelPoints { get; set; } = true;
private struct Extremum { public int BarIndex; public double Price; }
private List<Extremum> swingHighs = new List<Extremum>();
private List<Extremum> swingLows = new List<Extremum>();
private int lastBullPatternBar = -1;
private int lastBearPatternBar = -1;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Name = "WolfeWaveNT8_Opt";
IsOverlay = true;
Description = "Wolfe Wave para NinjaTrader 8 - optimizado";
}
}
protected override void OnBarUpdate()
{
if (CurrentBar < WaveLength) return;
// Detectar máximos y mínimos de swing una sola vez para esta barra
if (High[WaveLength / 2] == MAX(High, WaveLength)[WaveLength / 2])
{
int idx = CurrentBar - WaveLength / 2;
double price = High[WaveLength / 2];
// Evita añadir dos veces el mismo punto (por ejemplo en el primer ciclo)
if (swingHighs.Count == 0 || swingHighs[swingHighs.Count - 1].BarIndex != idx)
swingHighs.Add(new Extremum() { BarIndex = idx, Price = price });
if (swingHighs.Count > 20) swingHighs.RemoveAt(0);
}
if (Low[WaveLength / 2] == MIN(Low, WaveLength)[WaveLength / 2])
{
int idx = CurrentBar - WaveLength / 2;
double price = Low[WaveLength / 2];
if (swingLows.Count == 0 || swingLows[swingLows.Count - 1].BarIndex != idx)
swingLows.Add(new Extremum() { BarIndex = idx, Price = price });
if (swingLows.Count > 20) swingLows.RemoveAt(0);
}
// Wolfe Bullish
if (swingLows.Count >= 5)
{
var pts = swingLows.GetRange(swingLows.Count - 5, 5);
// Revisa si este patrón ya se dibujó (no lo repite)
if (pts[4].BarIndex != lastBullPatternBar)
{
// Patrón Wolfe básico: puedes ampliar reglas aquí a gusto
if (pts[0].Price < pts[2].Price&&pts[2].Price < pts[4].Price)
{
string tagBase = "BullWolfe_" + pts[0].BarIndex + "_" + pts[4].BarIndex;
// Limpia tags antiguos de este patrón si existen
for (int i = 0; i < 5; i++)
RemoveDrawObject("BullP" + (i + 1) + "_" + tagBase);
for (int i = 0; i < 4; i++)
RemoveDrawObject("BullWolfe" + i + "_" + tagBase);
RemoveDrawObject("BullTarget" + tagBase);
RemoveDrawObject("BullArrow" + tagBase);
// Dibuja líneas
for (int i = 0; i < 4; i++)
{
Draw.Line(
this,
"BullWolfe" + i + "_" + tagBase,
false,
CurrentBar - pts[i].BarIndex, pts[i].Price,
CurrentBar - pts[i + 1].BarIndex, pts[i + 1].Price,
Brushes.Orange, DashStyleHelper.Solid, 2
);
}
Draw.Line(
this,
"BullTarget" + tagBase,
false,
CurrentBar - pts[0].BarIndex, pts[0].Price,
CurrentBar - pts[3].BarIndex, pts[3].Price,
Brushes.Green, DashStyleHelper.Dash, 3
);
// Puntos y flecha solo si se solicita
if (LabelPoints)
{
for (int i = 0; i < 5; i++)
{
int barsAgo = CurrentBar - pts[i].BarIndex;
Draw.Text(
this,
"BullP" + (i + 1) + "_" + tagBase,
false,
(i + 1).ToString(),
barsAgo,
pts[i].Price - TickSize * 2,
0,
Brushes.Orange,
new SimpleFont("Arial", 13),
TextAlignment.Center,
Brushes.Transparent,
Brushes.Transparent,
100
);
}
// Flecha entrada en p5
Draw.ArrowUp(this, "BullArrow" + tagBase, false, 0, pts[4].Price - TickSize * 2, Brushes.Green);
}
lastBullPatternBar = pts[4].BarIndex;
}
}
}
// Wolfe Bearish
if (swingHighs.Count >= 5)
{
var pts = swingHighs.GetRange(swingHighs.Count - 5, 5);
if (pts[4].BarIndex != lastBearPatternBar)
{
if (pts[0].Price > pts[2].Price&&pts[2].Price > pts[4].Price)
{
string tagBase = "BearWolfe_" + pts[0].BarIndex + "_" + pts[4].BarIndex;
for (int i = 0; i < 5; i++)
RemoveDrawObject("BearP" + (i + 1) + "_" + tagBase);
for (int i = 0; i < 4; i++)
RemoveDrawObject("BearWolfe" + i + "_" + tagBase);
RemoveDrawObject("BearTarget" + tagBase);
RemoveDrawObject("BearArrow" + tagBase);
for (int i = 0; i < 4; i++)
{
Draw.Line(
this,
"BearWolfe" + i + "_" + tagBase,
false,
CurrentBar - pts[i].BarIndex, pts[i].Price,
CurrentBar - pts[i + 1].BarIndex, pts[i + 1].Price,
Brushes.Pink, DashStyleHelper.Solid, 2
);
}
Draw.Line(
this,
"BearTarget" + tagBase,
false,
CurrentBar - pts[0].BarIndex, pts[0].Price,
CurrentBar - pts[3].BarIndex, pts[3].Price,
Brushes.Red, DashStyleHelper.Dash, 3
);
if (LabelPoints)
{
for (int i = 0; i < 5; i++)
{
int barsAgo = CurrentBar - pts[i].BarIndex;
Draw.Text(
this,
"BearP" + (i + 1) + "_" + tagBase,
false,
(i + 1).ToString(),
barsAgo,
pts[i].Price + TickSize * 2,
0,
Brushes.Magenta,
new SimpleFont("Arial", 13),
TextAlignment.Center,
Brushes.Transparent,
Brushes.Transparent,
100
);
}
Draw.ArrowDown(this, "BearArrow" + tagBase, false, 0, pts[4].Price + TickSize * 2, Brushes.Red);
}
lastBearPatternBar = pts[4].BarIndex;
}
}
}
}
}
}