Untitled
unknown
csharp
8 months ago
19 kB
34
Indexable
#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 System.Text.Json.Serialization;
using System.Text.Json;
using NinjaTrader.Gui.Updater;
using System.Collections;
using SharpDX;
#endregion
//This namespace holds Indicators in this folder and is required. Do not change it.
namespace NinjaTrader.NinjaScript.Indicators
{
public class BetterSwing : Indicator
{
#region Properties
[NinjaScriptProperty]
[Display(Name = "Enable Swing Range Info", GroupName = "Parameters", Order = 0)]
public bool EnableSwingPowerDrawing { get; set; }
[NinjaScriptProperty]
[Display(Name = "Swing percentage", GroupName = "Swing Settings", Order = 1)]
[Range(0.01, 1)]
public double ZigZagPercentage { get; set; }
[NinjaScriptProperty]
[Display(Name = "Enable ZigZag", GroupName = "Parameters", Order = 2)]
public bool EnableZigZag { get; set; }
#endregion
private double tickSize;
private SwingLinkedList Swings;
public SwingLinkedList GetSwings
{
get
{
Update();
return Swings;
}
}
private ZigZag ZigZagIndicator;
// for fibo enum
private Dictionary<FibonacciLevels, double> fibDictionary;
public enum SwingType
{
SWING_LONG,
SWING_SHORT
}
public ZigZag GetZigZagInstance()
{
Update();
return ZigZagIndicator;
}
#region ClassMySwing
public class SwingLinkedList : IEnumerable<MySwing>
{
public MySwing Head { get; private set; }
public MySwing Tail { get; private set; }
public int Count { get; private set; }
public SwingLinkedList()
{
Head = null;
Tail = null;
}
public void Append(MySwing swing)
{
if (Head == null)
{
Head = swing;
Tail = swing;
}
else
{
Tail.Next = swing;
swing.Previous = Tail;
Tail = swing;
//if (owner != null)
//owner.Print("Dodano nowy Swing do listy");
}
Count++;
}
public override bool Equals(object obj)
{
if(obj is SwingLinkedList other)
{
if(this.Count != other.Count)
{
return false;
}
var thisNode = this.Head;
var otherNode = other.Head;
// 3. Iteracyjne porównanie każdego węzła
while (thisNode != null && otherNode != null)
{
if (!thisNode.Equals(otherNode)) // <-- PORÓWNANIE PRZEZ MySwing
return false;
thisNode = thisNode.Next;
otherNode = otherNode.Next;
}
return true; // Jeśli wszystkie węzły są równe, listy są równe
}
return false;
}
public override int GetHashCode()
{
unchecked
{
int hash = 17;
var node = this.Head;
while (node != null)
{
hash = hash * 31 + node.GetHashCode(); // Użycie hashcode MySwing
node = node.Next;
}
return hash;
}
}
// Implementacja interfejsu IEnumerable<MySwing>
public IEnumerator<MySwing> GetEnumerator()
{
MySwing current = Head;
while (current != null)
{
yield return current;
current = current.Next;
}
}
// Wymagana implementacja interfejsu IEnumerable
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class MySwing : IEquatable<MySwing>
{
public MySwing Previous { get; set; }
private MySwing? _next;
public MySwing Next
{
get
{
return _next;
}
set
{
if (value != null)
{
// Naprzemienność ekstremów w zależności od typu
if (this.SwingType == SwingType.SWING_LONG)
{
// Wymuszamy identyczny High
if (this.HighPrice != value.HighPrice)
throw new InvalidOperationException(
"Jeśli poprzedni swing był LONG, to następny (SHORT) musi mieć ten sam High."
);
}
else if (this.SwingType == SwingType.SWING_SHORT)
{
// Wymuszamy identyczny Low
if (this.LowPrice != value.LowPrice)
throw new InvalidOperationException(
"Jeśli poprzedni swing był SHORT, to następny (LONG) musi mieć ten sam Low."
);
}
}
// Link zwrotny
value.Previous = this;
_next = value;
}
}
// Cechy Swingu
public SwingType SwingType { get; }
// Get‐only property; ustalana tylko w konstruktorze
public double LowPrice { get; }
public double HighPrice { get; }
public double SwingRange { get; }
public DateTime LowTime { get; }
public DateTime HighTime { get; }
public MySwing(SwingType swingType, double lowPrice, double highPrice, double tickSize, DateTime lowTime, DateTime highTime)
{
SwingType = swingType;
LowPrice = lowPrice;
HighPrice = highPrice;
SwingRange = (highPrice - lowPrice) / tickSize;
LowTime = lowTime;
HighTime = highTime;
}
public double GetSwingPower(TimeSpan totalMinutes)
{
double duration = totalMinutes.TotalMinutes;
return (SwingRange / duration );
}
public SwingType GetSwingType()
{
return SwingType;
}
public static double GetFibLevel(SwingType swingType, double lowPrice, double highPrice, double level)
{
double priceAmplitude = Math.Abs(highPrice - lowPrice);
if (swingType == SwingType.SWING_SHORT)
{
// Swing short: poziom 0% jest na dole, 100% u g�ry
return highPrice - (priceAmplitude * (1 - level));
}
else if (swingType == SwingType.SWING_LONG)
{
// Swing long: poziom 0% jest na dole, 100% u g�ry
return lowPrice + (priceAmplitude * (1 - level));
}
else
{
throw new ArgumentException("Invalid swingType. Expected 'Up' or 'Down'.");
}
}
public double GetFibLevel(double level)
{
double priceAmplitude = Math.Abs(HighPrice - LowPrice);
if (SwingType == SwingType.SWING_SHORT)
{
return HighPrice - (priceAmplitude * (1 - level));
}
else if (SwingType == SwingType.SWING_LONG)
{
return LowPrice + (priceAmplitude * (1 - level)); ;
}
else
{
throw new ArgumentException("Invalid swingType. Expected 'Up' or 'Down'.");
}
}
// Equals + IEquatable
public override bool Equals(object obj) => Equals(obj as MySwing);
public bool Equals(MySwing other)
{
if (other == null)
return false;
return SwingType == other.SwingType
&& LowPrice.Equals(other.LowPrice)
&& HighPrice.Equals(other.HighPrice)
&& LowTime.Equals(other.LowTime)
&& HighTime.Equals(other.HighTime);
}
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + SwingType.GetHashCode();
hash = hash * 23 + LowPrice.GetHashCode();
hash = hash * 23 + HighPrice.GetHashCode();
hash = hash * 23 + LowTime.GetHashCode();
hash = hash * 23 + HighTime.GetHashCode();
return hash;
}
}
}
#endregion
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = @"Enter the description for your new custom Indicator here.";
Name = "BetterSwing";
Calculate = Calculate.OnBarClose;
IsOverlay = true;
DisplayInDataBox = true;
DrawOnPricePanel = true;
DrawHorizontalGridLines = true;
DrawVerticalGridLines = true;
PaintPriceMarkers = true;
ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right;
//Disable this property if your indicator requires custom values that cumulate with each new market data event.
//See Help Guide for additional information.
IsSuspendedWhileInactive = true;
AddPlot(Brushes.Blue, "ZigZag");
ZigZagPercentage = 0.25;
}
else if (State == State.Configure)
{
}
else if (State == State.DataLoaded)
{
tickSize = Instrument.MasterInstrument.TickSize;
Swings = new SwingLinkedList();
ZigZagIndicator = ZigZag(DeviationType.Percent, ZigZagPercentage, true);
}
}
protected override void OnBarUpdate()
{
if (BarsInProgress != 0) return;
if (CurrentBars[0] < 3)
{
return;
}
int currentLowIdx = -1, currentHighIdx = -1;
int previousLowIdx = -1, previousHighIdx = -1;
double currentLowPrice = 0, currentHighPrice = 0;
double previousLowPrice = 0, previousHighPrice = 0;
// pobranie indeksow ostatnich high and low - szukamy od "teraz"
currentLowIdx = ZigZagIndicator.LowBar(0, 1, CurrentBars[0] - 1);
currentHighIdx = ZigZagIndicator.HighBar(0, 1, CurrentBars[0] - 1);
// walidacja czy znaleziono indeksy
if (currentLowIdx == -1 || currentHighIdx == -1)
{
return;
}
// pobranie wartosci cen dla current swing
currentLowPrice = Low[currentLowIdx];
currentHighPrice = High[currentHighIdx];
DateTime currentLowTime = Time[currentLowIdx];
DateTime currentHighTime = Time[currentHighIdx];
// Tworzenie obiektu current Swing nie ma sensu, ponieważ aktualny Swing aktualizuje sie na bieżąco, więc tylko marnujemy pamięc na stercie
//CurrentSwing = new MySwing(currentLowIdx, currentLowPrice, currentLowTime, currentHighIdx, currentHighPrice, currentHighTime, tickSize);
if(currentHighTime < currentLowTime) {
// Jezeli czas szczytu aktualnie rozwijajacego sie Swingu jest mniejszy (wczesniejszy) niz czas low to znaczy ze to ruch spadkowy
previousHighIdx = currentHighIdx;
previousLowIdx = ZigZagIndicator.LowBar(previousHighIdx - 1, 1, CurrentBars[0] - 1);
} else {
// W odwrotnym przypadku jest to ruch wzrostowy
previousLowIdx = currentLowIdx;
previousHighIdx = ZigZagIndicator.HighBar(previousLowIdx - 1, 1, CurrentBars[0] - 1);
}
if (previousLowIdx < 0 || previousHighIdx < 0)
{
return;
}
previousLowPrice = Low[previousLowIdx];
previousHighPrice = High[previousHighIdx];
DateTime previousLowTime = Time[previousLowIdx];
DateTime previousHighTime = Time[previousHighIdx];
MySwing FormedSwing;
if (previousLowTime < previousHighTime)
{
// Jezeli czas szczytu poprzedniego Swingu jest mniejszy (wczesniejszy) niz czas low to znaczy ze to ruch spadkowy
FormedSwing = new MySwing(SwingType.SWING_LONG,
previousLowPrice,
previousHighPrice,
tickSize, previousLowTime, previousHighTime);
//Print("Utworzono swing wzrostowy");
}
else
{
// W odwrotnym przypadku jest to ruch wzrostowy
//PreviousSwing = new MySwing(SwingType.SWING_LONG, previousLowPrice, previousHighPrice, tickSize);
FormedSwing = new MySwing(SwingType.SWING_SHORT,
previousLowPrice,
previousHighPrice,
tickSize, previousLowTime, previousHighTime);
//Print("Utworzono swing spadkowy");
}
var lastSwing = Swings.Tail;
if (lastSwing != null && lastSwing.Equals(FormedSwing))
{
// Oznacza, że parametry (SwingType, LowPrice, HighPrice) są takie same,
// więc pomijamy dodanie do listy
//Print("Znaleziono duplikat swingu, pomijamy...");
}
else
{
try
{
Swings.Append(FormedSwing);
}
catch (ArgumentException e)
{
//Print(e.Message);
}
catch (InvalidOperationException e)
{
//Print(e.Message);
}
if (Swings.Count == 0)
{
//Print("Lista jest pusta");
}
}
}
}
}
#region NinjaScript generated code. Neither change nor remove.
namespace NinjaTrader.NinjaScript.Indicators
{
public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
{
private BetterSwing[] cacheBetterSwing;
public BetterSwing BetterSwing(bool enableSwingPowerDrawing, double zigZagPercentage, bool enableZigZag)
{
return BetterSwing(Input, enableSwingPowerDrawing, zigZagPercentage, enableZigZag);
}
public BetterSwing BetterSwing(ISeries<double> input, bool enableSwingPowerDrawing, double zigZagPercentage, bool enableZigZag)
{
if (cacheBetterSwing != null)
for (int idx = 0; idx < cacheBetterSwing.Length; idx++)
if (cacheBetterSwing[idx] != null && cacheBetterSwing[idx].EnableSwingPowerDrawing == enableSwingPowerDrawing && cacheBetterSwing[idx].ZigZagPercentage == zigZagPercentage && cacheBetterSwing[idx].EnableZigZag == enableZigZag && cacheBetterSwing[idx].EqualsInput(input))
return cacheBetterSwing[idx];
return CacheIndicator<BetterSwing>(new BetterSwing(){ EnableSwingPowerDrawing = enableSwingPowerDrawing, ZigZagPercentage = zigZagPercentage, EnableZigZag = enableZigZag }, input, ref cacheBetterSwing);
}
}
}
namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
{
public Indicators.BetterSwing BetterSwing(bool enableSwingPowerDrawing, double zigZagPercentage, bool enableZigZag)
{
return indicator.BetterSwing(Input, enableSwingPowerDrawing, zigZagPercentage, enableZigZag);
}
public Indicators.BetterSwing BetterSwing(ISeries<double> input , bool enableSwingPowerDrawing, double zigZagPercentage, bool enableZigZag)
{
return indicator.BetterSwing(input, enableSwingPowerDrawing, zigZagPercentage, enableZigZag);
}
}
}
namespace NinjaTrader.NinjaScript.Strategies
{
public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
{
public Indicators.BetterSwing BetterSwing(bool enableSwingPowerDrawing, double zigZagPercentage, bool enableZigZag)
{
return indicator.BetterSwing(Input, enableSwingPowerDrawing, zigZagPercentage, enableZigZag);
}
public Indicators.BetterSwing BetterSwing(ISeries<double> input , bool enableSwingPowerDrawing, double zigZagPercentage, bool enableZigZag)
{
return indicator.BetterSwing(input, enableSwingPowerDrawing, zigZagPercentage, enableZigZag);
}
}
}
#endregion
Editor is loading...
Leave a Comment