Re: Resolviendo el TimeFrame
Publicado: 09 Jul 2025 12:18
6E 8/7/25
¿Dudas sobre trading? Plantea tus cuestiones sobre el funcionamiento del mercado, descarga indicadores y sistemas de trading y comparte tus operaciones con otros traders.
https://www.x-trader.net/foro/
Código: Seleccionar todo
#region Using declarations
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Data;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.Tools;
using NinjaTrader.NinjaScript.DrawingTools;
using NinjaTrader.NinjaScript.Indicators;
#endregion
namespace NinjaTrader.NinjaScript.Indicators
{
/// <summary>
/// This is the Sine Wave indicator as was introduced by John Ehlers in his books.
/// There are two versions for this indicator that differ in the way calculating the cycles, each method is from a different book:
/// 1) Rocket Science for Traders: Digital Signal Processing Applications by John F. Ehlers (Jul 20, 2001)
/// 2) Cybernetic Analysis for Stocks and Futures: Cutting-Edge DSP Technology to Improve Your Trading (by John F. Ehlers (Mar 29, 2004)
/// </summary>
[TypeConverter("NinjaTrader.NinjaScript.Indicators.SWConverter")]
public class SW : Indicator
{
#region Variables
private Series<double> Cycle, DCPhase, DeltaPhase, Detrender, I1, I2, im, InstPeriod, period, Q1, Q2, re, Smooth, SmoothNum, V1;
private bool drawingSupport;
private double MedianDelta, DC, currDotValue;
private int DCPeriod, yPixels;
private string dotText;
private SimpleFont pfont = new SimpleFont("Wingdings", 4) {Bold = true};
private Brush currDotColor;
#endregion
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = "Sine Wave indicator by John Ehlers, v0.725 by fercho";
Name = "SW";
IsSuspendedWhileInactive = true;
Calculate = Calculate.OnEachTick;
BarsRequiredToPlot = 0;
Alpha = 0.07;
PriceSmoothPeriod = 4;
SupportColor = Brushes.Magenta;
ResistanceColor = Brushes.Blue;
AddPlot(new Stroke(Brushes.Red), PlotStyle.Line, "LeadSine");
AddPlot(new Stroke(Brushes.Blue), PlotStyle.Line, "Sine");
}
else if (State == State.Configure)
{
drawingSupport = true;
yPixels = 0;
dotText = "l";
}
else if (State == State.DataLoaded)
{
Cycle = new Series<double>(this);
DCPhase = new Series<double>(this);
DeltaPhase = new Series<double>(this);
Detrender = new Series<double>(this);
I1 = new Series<double>(this);
I2 = new Series<double>(this);
im = new Series<double>(this);
InstPeriod = new Series<double>(this);
period = new Series<double>(this);
Q1 = new Series<double>(this);
Q2 = new Series<double>(this);
re = new Series<double>(this);
Smooth = new Series<double>(this);
SmoothNum = new Series<double>(this);
V1 = new Series<double>(this);
}
}
protected override void OnBarUpdate()
{
bool res = false;
switch(SWM)
{
case SineWaveMethod.RocketScience:
res = RocketScience();
break;
default:
res = CyberneticsAnalysis();
break;
}
if (res && DrawSupportResistance)
{
// If we are drawing support and now the Leadsine is BELOW the since it meand we need to draw resistance.
if (drawingSupport && LeadSine[0] < Sine[0])
{
// The LeadSince crossed below the Sine meaning we have a cycle top, we draw
// the resistance only we get a low lower than the previous one confirming the
// down move started.
if (Low[0] < Low[1])
{
currDotValue = High[1];
currDotColor = ResistanceColor;
drawingSupport = false;
}
}
else if (!drawingSupport && LeadSine[0] > Sine[0])
{
if (High[0] > High[1])
{
currDotValue = Low[1];
currDotColor = SupportColor;
drawingSupport = true;
}
}
Draw.Text(this,"dot"+CurrentBar.ToString(), true, dotText, 0, currDotValue, yPixels, currDotColor, pfont, TextAlignment.Center, Brushes.Transparent, Brushes.Transparent, 10);
}
}
protected bool CyberneticsAnalysis()
{
if (CurrentBar < 3)
return false;
Smooth[0] = (Median[0] + 2*Median[1] + 2*Median[2] + Median[3])/6;
if (CurrentBar < 6)
{
Cycle[0] = (Median[0] - 2*Median[1] + Median[2])/4;
return false;
}
else
{
double d = (1 - 0.5*Alpha)*(1 - 0.5*Alpha)*(Smooth[0] - 2*Smooth[1] + Smooth[2]) + 2*(1 - Alpha)*Cycle[1] - (1 - Alpha)*(1 - Alpha)*Cycle[2];
Cycle[0] = d;
}
Q1[0] = (0.0962*Cycle[0] + 0.5769*Cycle[2] - 0.5769*Cycle[4] - 0.0962*Cycle[6])*(0.5 + 0.08*InstPeriod[1]);
I1[0] = Cycle[3];
if (Q1[0] != 0 && Q1[1] != 0)
{
DeltaPhase[0] = (I1[0]/Q1[0] - I1[1]/Q1[1])/(1 + I1[0]*I1[1]/(Q1[0]*Q1[1]));
}
if (DeltaPhase[0] < 0.1)
DeltaPhase[0] = 0.1;
else if (DeltaPhase[0] > 1.1)
DeltaPhase[0] = 1.1;
MedianDelta = GetMedian(DeltaPhase, 5);
if (MedianDelta == 0)
DC = 15;
else
DC = 6.28318/MedianDelta + 0.5;
InstPeriod[0] = 0.33*DC + 0.67*InstPeriod[1];
V1[0] = 0.15*InstPeriod[0] + 0.85*V1[1];
DCPeriod = (int)Math.Floor(V1[0]);
double RealPart = 0, ImagPart = 0;
for (int i = 0; i < Math.Min(DCPeriod, CurrentBar + 1); ++i)
{
RealPart = RealPart + Math.Sin((Math.PI/180)*(360*i/DCPeriod))*Cycle[i];
ImagPart = ImagPart + Math.Cos((Math.PI/180)*(360*i/DCPeriod))*Cycle[i];
}
if (Math.Abs(ImagPart) > 0.001)
DCPhase[0] = (180/Math.PI)*Math.Atan(RealPart/ImagPart);
else
DCPhase[0] = 90*Math.Sign(RealPart);
DCPhase[0] += 90;
if (ImagPart < 0) DCPhase[0] += 180;
if (DCPhase[0] > 315) DCPhase[0] -= 360;
Sine[0] = Math.Sin((Math.PI/180)*(DCPhase[0]));
LeadSine[0] = Math.Sin((Math.PI/180)*(DCPhase[0] + 45));
return true;
}
private bool RocketScience()
{
// need 7 Bars to start computing.
if (CurrentBar < 3)
return false;
Smooth[0] = GetSmoothedPrice(Median);
if (CurrentBar < 6)
return false;
Detrender[0] = (0.0962*Smooth[0]+0.5769*Smooth[2] -
0.5769*Smooth[4] - 0.0962*Smooth[6])*(0.075*period[1] + 0.54);
// Compute InPhase and Quadrature components
Q1[0] = (0.0962*Detrender[0] + 0.5769*Detrender[2] -
0.5769*Detrender[4] - 0.0962*Detrender[6])*(0.075*period[1] + 0.54);
I1[0] = Detrender[3];
// Advance the phase of i1 and q1 by 90}
double jI = (0.0962*I1[0] + 0.5769*I1[2] - 0.5769*I1[4] - 0.0962*I1[6])*(0.075*period[1] + 0.54);
double jQ = (0.0962*Q1[0] + 0.5769*Q1[2] - 0.5769*Q1[4] - 0.0962*Q1[6])*(0.075*period[1] + 0.54);
// Phasor addition for 3 bar averaging}
I2[0] = I1[0] - jQ;
Q2[0] = Q1[0] + jI;
// Smooth the I and Q components before applying the discriminator
I2[0] = 0.2*I2[0] + 0.8*I2[1];
Q2[0] = 0.2*Q2[0] + 0.8*Q2[1];
// Homodyne Discriminator
re[0] = I2[0]*I2[1] + Q2[0]*Q2[1];
im[0] = I2[0]*Q2[1] - Q2[0]*I2[1];
re[0] = 0.2*re[0] + 0.8*re[1];
im[0] = 0.2*im[0] + 0.8*im[1];
if (im[0] != 0 && re[0] != 0) period[0] = 360/((180/Math.PI)*Math.Atan(im[0]/re[0])); // Convert Atan return from rad to deg
if (period[0] > 1.5 *period[1]) period[0] = 1.5*period[1];
if (period[0] < 0.67*period[1]) period[0] = 0.67*period[1];
if (period[0] < 6) period[0] = 6;
if (period[0] > 50) period[0] = 50;
period[0] = 0.2* period[0] + 0.8*period[1];
SmoothNum[0] = 0.33*period[0] + 0.67*SmoothNum[1];
// Compute dominant cycle phase
DCPeriod = (int)Math.Floor( SmoothNum[0] + 0.5);
double RealPart = 0, ImagPart = 0;
for(int count = 0; count < Math.Min(DCPeriod, CurrentBar + 1); count++)
{
RealPart += Math.Cos( (Math.PI/180)*( 360*count/DCPeriod) )*Smooth[count]; // Math.Sin requires input in rad
ImagPart += Math.Sin( (Math.PI/180)*( 360*count/DCPeriod) )*Smooth[count]; // Math.Cos requires input in rad
}
if (Math.Abs(RealPart) > 0)
{
DCPhase[0] = (180/Math.PI)*Math.Atan( ImagPart/RealPart ); // Convert Atan return from rad to deg
}
if (Math.Abs(RealPart) <= 0.001)
{
DCPhase[0] = (90*Math.Sign(ImagPart));
}
DCPhase[0] += 90;
DCPhase[0] = DCPhase[0] + (360/SmoothNum[0]);
if (RealPart < 0)
{
DCPhase[0] += 180;
}
if (DCPhase[0] > 315)
{
DCPhase[0] = DCPhase[0] - 360;
}
Sine[0] = Math.Sin((Math.PI/180)*DCPhase[0])*100;
LeadSine[0] = Math.Sin((Math.PI/180)*(DCPhase[0] + 45))*100;
return true;
}
private double GetSmoothedPrice(ISeries<double> data)
{
switch (SM)
{
case SmoothMethod.SMA:
return SMA(data, PriceSmoothPeriod)[0];
case SmoothMethod.HMA:
return HMA(data, PriceSmoothPeriod)[0];
case SmoothMethod.VWMA:
return VWMA(data, PriceSmoothPeriod)[0];
case SmoothMethod.WMA:
default:
return WMA(data, PriceSmoothPeriod)[0];
}
}
#region Properties
[Browsable(false)]
[XmlIgnore()]
public Series<double> LeadSine
{
get { return Values[0]; }
}
[Browsable(false)]
[XmlIgnore()]
public Series<double> Sine
{
get { return Values[1]; }
}
[RefreshProperties(RefreshProperties.All)]
[Display(Name = "Draw Support/Resistance", GroupName = "Appearance", Order = 0)]
public bool DrawSupportResistance
{ get; set; }
[XmlIgnore()]
[NinjaScriptProperty]
[Display(Name = "Support Color", Description = "Determines the support dots color.", GroupName = "Appearance", Order = 1)]
public Brush SupportColor
{ get; set; }
[XmlIgnore()]
[NinjaScriptProperty]
[Display(Name = "Resistance Color", Description = "Determines the resistance dots color.", GroupName = "Appearance", Order = 2)]
public Brush ResistanceColor
{ get; set; }
[RefreshProperties(RefreshProperties.All)]
[Display(Name = "Sine Wave Method", GroupName = "Parameters", Order = 0)]
public SineWaveMethod SWM
{ get; set; }
[Range(0, double.MaxValue), NinjaScriptProperty]
[Display(ResourceType = typeof(Custom.Resource), Name = "Alpha", GroupName = "Parameters", Order = 1)]
public double Alpha
{ get; set; }
[Range(1, int.MaxValue), NinjaScriptProperty]
[Display(ResourceType = typeof(Custom.Resource), Name = "Price Smooth Period", GroupName = "Parameters", Order = 2)]
public int PriceSmoothPeriod
{ get; set; }
[NinjaScriptProperty]
[Display(Name = "Smooth Method", GroupName = "Parameters", Order = 3)]
public SmoothMethod SM
{ get; set; }
#endregion
}
#region Show/hide
public class SWConverter : IndicatorBaseConverter
{
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object component, Attribute[] attrs)
{
SW indicator = component as SW;
PropertyDescriptorCollection propertyDescriptorCollection = base.GetPropertiesSupported(context) ?
base.GetProperties(context, component, attrs) :
TypeDescriptor.GetProperties(component, attrs);
if (indicator == null || propertyDescriptorCollection == null)
return propertyDescriptorCollection;
PropertyDescriptor supportColor = propertyDescriptorCollection["SupportColor"];
PropertyDescriptor resistanceColor = propertyDescriptorCollection["ResistanceColor"];
PropertyDescriptor alpha = propertyDescriptorCollection["Alpha"];
PropertyDescriptor priceSmoothPeriod= propertyDescriptorCollection["PriceSmoothPeriod"];
propertyDescriptorCollection.Remove(supportColor);
propertyDescriptorCollection.Remove(resistanceColor);
propertyDescriptorCollection.Remove(alpha);
propertyDescriptorCollection.Remove(priceSmoothPeriod);
if (indicator.DrawSupportResistance)
{
propertyDescriptorCollection.Add(supportColor);
propertyDescriptorCollection.Add(resistanceColor);
}
if (indicator.SWM == SineWaveMethod.CyberneticsAnalysis)
propertyDescriptorCollection.Add(alpha);
else
propertyDescriptorCollection.Add(priceSmoothPeriod);
return propertyDescriptorCollection;
}
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{ return true; }
}
#endregion
}
#region Public Enum
public enum SineWaveMethod
{
CyberneticsAnalysis = 0,
RocketScience = 1
}
public enum SmoothMethod
{
SMA = 0,
HMA = 1,
VWMA = 2,
WMA = 3
}
#endregion
HolaX-Trader escribió: 13 Jul 2025 20:16 Hola Fernando70,
Reconozco que llevo varios días intrigado por este hilo porque, ¿cómo se puede optimizar el timeframe cada día y más en segundos? Reconozco que hasta la fecha había visto traders que usaban timeframes ligeramente diferentes al resto (2, 3, 7, 11 o 13 minutos para adelantarse al comportamiento de timeframes más estándar) y lógicamente diferentes tipos de velas como las basadas en ticks o las de equivolumen, pero hasta ahora no había visto nada igual.
Lo que no acabo de ver tan claro es la ventaja práctica de esta optimización del valor del timeframe (al menos, no en los ejemplos que has puesto hasta ahora), ¿podrías hacer un ejemplo explicado con más detalle? Y ya puestos, y aunque me imagino que no contarás todo, ¿puedes dar una idea de en qué se basa esa optimización del valor del timeframe? Gracias.
Saludos,
X-Trader