DA
Topics
07 Mar 2019, 21:46
1812
7
Replies
daniel.agg
08 Mar 2019, 10:07
That's strange, the .cs files should have been in the corresponding subfolders.
Anyway, here's the bot:
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.Internet)]
public class MACDTestBot : Robot
{
#region indicator parameters
[Parameter("Divergence Ledge", DefaultValue = 3, MinValue = 1, MaxValue = 10, Step = 1)]
public int Divergence_Ledge { get; set; }
[Parameter("Divergence Extremums", DefaultValue = false)]
public bool Divergence_Extremums { get; set; }
[Parameter("Divergence Min Length", DefaultValue = 6, MinValue = 4, MaxValue = 10, Step = 1)]
public int Divergence_Min_Length { get; set; }
[Parameter("Last Points", DefaultValue = 3, MinValue = 1, MaxValue = 10, Step = 1)]
public int Last_Points { get; set; }
[Parameter("MACD: Short Cycle", DefaultValue = 12)]
public int MACD_Short_Cycle { get; set; }
[Parameter("MACD: Long Cycle", DefaultValue = 26)]
public int MACD_Long_Cycle { get; set; }
[Parameter("MACD: Signal Period", DefaultValue = 9)]
public int MACD_Signal_Period { get; set; }
[Parameter("MACD: Reverse", DefaultValue = false)]
public bool MACD_Reverse { get; set; }
#endregion
private MACDDivergence indicator;
private int indicatorDataCount;
protected override void OnStart()
{
indicator = Indicators.GetIndicator<MACDDivergence>(
Divergence_Ledge,
Divergence_Extremums,
Divergence_Min_Length,
Last_Points,
MACD_Short_Cycle,
MACD_Long_Cycle,
MACD_Signal_Period,
MACD_Reverse);
indicatorDataCount = indicator.Data.Count();
}
protected override void OnTick()
{
if(indicatorDataCount != indicator.Data.Count())
{
// do something
}
}
protected override void OnStop()
{
// Put your deinitialization logic here
}
}
}
And here's the indicator:
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
//using System.Linq;
using System.Collections.Generic;
namespace cAlgo.Indicators
{
[Indicator(TimeZone = TimeZones.UTC, IsOverlay = false, AutoRescale = true, ScalePrecision = 7, AccessRights = AccessRights.None)]
public class MACDDivergence : Indicator
{
[Parameter("Divergence Ledge", DefaultValue = 3, MinValue = 1, MaxValue = 10, Step = 1)]
public int Divergence_Ledge { get; set; }
[Parameter("Divergence Extremums", DefaultValue = false)]
public bool Divergence_Extremums { get; set; }
[Parameter("Divergence Min Length", DefaultValue = 6, MinValue = 4, MaxValue = 10, Step = 1)]
public int Divergence_Min_Length { get; set; }
[Parameter("Last Points", DefaultValue = 3, MinValue = 1, MaxValue = 10, Step = 1)]
public int Last_Points { get; set; }
[Parameter("MACD: Short Cycle", DefaultValue = 12)]
public int MACD_Short_Cycle { get; set; }
[Parameter("MACD: Long Cycle", DefaultValue = 26)]
public int MACD_Long_Cycle { get; set; }
[Parameter("MACD: Signal Period", DefaultValue = 9)]
public int MACD_Signal_Period { get; set; }
[Parameter("MACD: Reverse", DefaultValue = false)]
public bool MACD_Reverse { get; set; }
[Output("Main", PlotType = PlotType.Histogram, Color = Colors.DeepSkyBlue)]
public IndicatorDataSeries Result { get; set; }
/// Indicator
private MacdHistogram I_MACD;
/// Properties
string Chart_Object_Title = "MACD Divergence";
private DivergenceType HIGH = DivergenceType.High;
private DivergenceType LOW = DivergenceType.Low;
private ExtremumActionType for_Update = ExtremumActionType.Update;
private ExtremumActionType for_New = ExtremumActionType.New;
/// Data to use in Bot
private List<Label> High_Extremums = new List<Label>();
private List<Label> Low_Extremums = new List<Label>();
public List<Divergence> Data = new List<Divergence>();
public List<TrendType> Trend = new List<TrendType>();
/// Models
public struct Divergence
{
public DivergenceType T;
public Label A;
public Label B;
public Divergence(DivergenceType _Type = DivergenceType.None, Label Label_A = new Label(), Label Label_B = new Label())
{
T = _Type;
A = Label_A;
B = Label_B;
}
public string Text
{
get { return string.Format("- A - {0} - B - {1}", A.Text, B.Text); }
}
public Colors Color
{
get
{
switch (T)
{
case DivergenceType.High:
return Colors.SpringGreen;
break;
case DivergenceType.Low:
return Colors.DeepPink;
break;
default:
return Colors.Yellow;
break;
}
}
}
}
public struct Label
{
public Point MACD;
public Point MS;
public Label(Point M1 = new Point(), Point M2 = new Point())
{
MACD = M1;
MS = M2;
}
public string Text
{
get { return string.Format("MACD = {0} MS = {1}", MACD.Text, MS.Text); }
}
}
public struct Point
{
public int Index;
public double Value;
public Point(int I = 0, double V = 0)
{
Index = I;
Value = V;
}
public string Text
{
get { return string.Format("{0} ({1})", Value.ToString("N6"), Index); }
}
}
public enum ExtremumActionType
{
Update,
New
}
public enum DivergenceType
{
High,
Low,
None
}
public enum TrendType
{
Up,
Down,
None
}
/// TODO: Init
protected override void Initialize()
{
I_MACD = Indicators.MacdHistogram(MACD_Short_Cycle, MACD_Long_Cycle, MACD_Signal_Period);
Print("MACD Divergence Calculator is initialized. Results = {0} Data = {1} Data_Trend = {2}", Result.Count, Data.Count, Trend.Count);
}
/// TODO: Indicator
public override void Calculate(int index)
{
/// MACD Calc
Result[index] = MACD_Reverse ? I_MACD.Histogram[index] - I_MACD.Signal[index] : I_MACD.Signal[index] - I_MACD.Histogram[index];
/// MACD Divergence
if (index <= Divergence_Ledge)
return;
/// TODO: High Divergence
Point MACD_Max = Max_MACD(From: index - 1, For_Last_Bars: Divergence_Ledge);
Point MS_Max = Max_MS(From: index - 1, For_Last_Bars: Divergence_Ledge);
Label Max = new Label(MACD_Max, MS_Max);
if (High_Extremums.Count == 0)
{
if (Is_Max(L: Max, At: index))
Update_Data(Stage: "1 Step: FIRST", _Type: HIGH, New_Extremum: Max, At: index, Action: for_New);
}
else
{
Label Last = High_Extremums[High_Extremums.Count - 1];
if (Math.Max(Max.MACD.Index, Max.MS.Index) - Last.MACD.Index <= Divergence_Min_Length)
{
//if (Last.MACD.Value < MACD(index) && Last.MACD.Index == index - 1 && Max.MACD.Index - Last.MACD.Index <= Divergence_Ledge)
//{
// Max.MACD.Value = MACD(index);
// Max.MACD.Index = index;
// Update_Data(Stage: "3 Step: update NOW", _Type: HIGH, New_Extremum: Max, At: index, Action: for_Update);
//}
if (Allow_To_Update_High(L: Last, New: Max, At: index))
Update_Data(Stage: "3 Step: update LAST", _Type: HIGH, New_Extremum: Max, At: index, Action: for_Update);
}
else if (Is_Next_High_Wave(A: Last, B: Max, At: index))
Update_Data(Stage: "4 Step: NEW", _Type: HIGH, New_Extremum: Max, At: index, Action: for_New);
}
/// TODO: Low Divergence
Point MACD_Min = Min_MACD(From: index - 1, For_Last_Bars: Divergence_Ledge);
Point MS_Min = Min_MS(From: index - 1, For_Last_Bars: Divergence_Ledge);
Label Min = new Label(MACD_Min, MS_Min);
if (Low_Extremums.Count == 0)
{
if (Is_Min(L: Min, At: index))
Update_Data(Stage: "1 Step: FIRST", _Type: LOW, New_Extremum: Min, At: index, Action: for_New);
}
else
{
Label Last = Low_Extremums[Low_Extremums.Count - 1];
if (Math.Max(Min.MACD.Index, Min.MS.Index) - Last.MACD.Index <= Divergence_Min_Length)
{
//if (Last.MACD.Value < MACD(index) && Last.MACD.Index == index - 1 && Min.MACD.Index - Last.MACD.Index <= Divergence_Ledge)
//{
// Min.MACD.Value = MACD(index);
// Min.MACD.Index = index;
// Update_Data(Stage: "3 Step: update NOW", _Type: LOW, New_Extremum: Min, At: index, Action: for_Update);
//}
if (Allow_To_Update_Low(L: Last, New: Min, At: index))
Update_Data(Stage: "3 Step: update LAST", _Type: LOW, New_Extremum: Min, At: index, Action: for_Update);
}
else if (Is_Next_Low_Wave(A: Last, B: Min, At: index))
Update_Data(Stage: "4 Step: NEW", _Type: LOW, New_Extremum: Min, At: index, Action: for_New);
}
/// Update Trend List
if (Trend.Count == 0)
while (Trend.Count < index)
Trend.Add(TrendType.None);
if (Data.Count > 0)
{
Divergence D = Data[Data.Count - 1];
bool T_High = D.T == DivergenceType.High;
bool T_Low = D.T == DivergenceType.Low;
TrendType T = T_High ? TrendType.Down : (T_Low ? TrendType.Up : TrendType.None);
if (Trend.Count < index)
Trend.Add(T);
else if (Trend.Count - 1 == index)
Trend[index] = T;
}
else
{
TrendType T = TrendType.None;
if (Trend.Count < index)
Trend.Add(T);
else if (Trend.Count - 1 == index)
Trend[index] = T;
}
}
/// Methods
/// Info
private void Info(string Stage, Label Last, Label Extremum, int At, DivergenceType _Type)
{
//if (IsBacktesting)
// return;
Print("{0} - {1} - {2} - {3} - {4} - Last {5} - Extremum {6}", At, MarketSeries.OpenTime[At].Date.ToShortDateString(), Data.Count, _Type.ToString(), Stage, Last.Text, Extremum.Text);
}
/// Update list Data_Divergence
private void Update_Data(string Stage, DivergenceType _Type, Label New_Extremum, int At, ExtremumActionType Action)
{
if (_Type == HIGH ? High_Extremums.Count > 0 : Low_Extremums.Count > 0)
{
Label Previous_Extremum = _Type == HIGH ? High_Extremums[High_Extremums.Count - 1] : Low_Extremums[Low_Extremums.Count - 1];
Info(Stage: Stage, Last: Previous_Extremum, Extremum: New_Extremum, At: At, _Type: _Type);
if (Action == for_New)
if (_Type == HIGH)
High_Extremums.Add(New_Extremum);
else if (_Type == LOW)
Low_Extremums.Add(New_Extremum);
Label Last_Extremum = _Type == HIGH ? High_Extremums[High_Extremums.Count - 1] : Low_Extremums[Low_Extremums.Count - 1];
int N_Extremums = _Type == HIGH ? High_Extremums.Count - 1 : Low_Extremums.Count - 1;
for (int Index = Math.Max(N_Extremums - Last_Points, 0); Index < N_Extremums; Index++)
{
Label Current_Extremum = _Type == HIGH ? High_Extremums[Index] : Low_Extremums[Index];
Divergence Last = new Divergence(_Type: _Type, Label_A: Current_Extremum, Label_B: Last_Extremum);
Divergence New = new Divergence(_Type: _Type, Label_A: Current_Extremum, Label_B: New_Extremum);
if (No_Obstacles(D: New) && Is_Divergence(D: New))
{
if (Data.Contains(Last))
{
int D_Index = Data.IndexOf(Last);
Data[D_Index] = New;
Info(Stage: "7 Step: update DATA", Last: Current_Extremum, Extremum: New_Extremum, At: At, _Type: _Type);
Draw(D: New, Prefix: D_Index.ToString());
}
else if (!Data.Exists(D => D.B.MACD.Index == New.B.MACD.Index))
{
Data.Add(New);
Info(Stage: "7 Step: new DATA", Last: Current_Extremum, Extremum: New_Extremum, At: At, _Type: _Type);
Draw(D: New, Prefix: (Data.Count - 1).ToString());
}
}
else if (Data.Contains(Last))
{
Info(Stage: "7 Step: remove DATA", Last: Current_Extremum, Extremum: New_Extremum, At: At, _Type: _Type);
Remove(D: Last, Prefix: Data.IndexOf(Last).ToString());
Data.Remove(Last);
}
}
}
else
{
if (Action == for_New)
if (_Type == HIGH)
High_Extremums.Add(New_Extremum);
else if (_Type == LOW)
Low_Extremums.Add(New_Extremum);
}
if (Action == for_Update)
if (_Type == HIGH)
High_Extremums[High_Extremums.Count - 1] = New_Extremum;
else if (_Type == LOW)
Low_Extremums[Low_Extremums.Count - 1] = New_Extremum;
}
/// Draw and remove chart objects
private void Draw(Divergence D, string Prefix)
{
//if (IsBacktesting)
// return;
string Name = Prefix + Chart_Object_Title + D.T.ToString() + D.A.MACD.Index.ToString();
int Index_1 = D.A.MACD.Index;
int Index_2 = D.B.MACD.Index;
double Value_1 = D.A.MACD.Value;
double Value_2 = D.B.MACD.Value;
Colors Color = D.Color;
ChartObjects.DrawLine(Name, Index_1, Value_1, Index_2, Value_2, Color);
ChartObjects.DrawText(Name + "A", "•", Index_1, Value_1, VerticalAlignment.Center, HorizontalAlignment.Center, Color);
ChartObjects.DrawText(Name + "B", "•", Index_2, Value_2, VerticalAlignment.Center, HorizontalAlignment.Center, Color);
Info(Stage: "Draw Divergence:", Last: D.A, Extremum: D.B, At: D.A.MACD.Index, _Type: D.T);
}
private void Remove(Divergence D, string Prefix)
{
//if (IsBacktesting)
// return;
string Name = Prefix + Chart_Object_Title + D.T.ToString() + D.A.MACD.Index.ToString();
ChartObjects.RemoveObject(Name);
ChartObjects.RemoveObject(Name + "A");
ChartObjects.RemoveObject(Name + "B");
}
/// Helpers
private double MACD(int Index)
{
return Result[Index];
}
private bool Is_Divergence(Divergence D)
{
bool T1 = D.A.MACD.Value >= D.B.MACD.Value && D.A.MS.Value < D.B.MS.Value;
bool T2 = D.A.MACD.Value <= D.B.MACD.Value && D.A.MS.Value > D.B.MS.Value;
bool T_P = D.T == HIGH ? D.A.MACD.Value > 0 : D.A.MACD.Value < 0;
return (T1 || T2) && T_P;
}
/// Is Max
private bool Is_Max(Label L, int At)
{
return (MACD_Is_Max(P: L.MACD, At: At) && MS_Is_Max(P: L.MS, At: At));
}
private bool MACD_Is_Max(Point P, int At)
{
return P.Value > 0 && P.Value > MACD(At) && P.Value > MACD(P.Index - 1);
}
private bool MS_Is_Max(Point P, int At)
{
return P.Value > MS_High(At) && P.Value > MS_High(P.Index - 1);
}
/// Is Min
private bool Is_Min(Label L, int At)
{
return (MACD_Is_Min(P: L.MACD, At: At) && MS_Is_Min(P: L.MS, At: At));
}
private bool MACD_Is_Min(Point P, int At)
{
return P.Value < 0 && P.Value < MACD(At) && P.Value < MACD(P.Index - 1);
}
private bool MS_Is_Min(Point P, int At)
{
return P.Value < MS_High(At) && P.Value < MS_High(P.Index - 1);
}
/// Allow to update
private bool Allow_To_Update_High(Label L, Label New, int At)
{
if (New.MACD.Index == At)
return false;
if ((L.MACD.Value < New.MACD.Value && MACD_Is_Max(P: New.MACD, At: At)) || (L.MS.Value < New.MS.Value && MS_Is_Max(P: New.MS, At: At)))
return true;
return false;
}
private bool Allow_To_Update_Low(Label L, Label New, int At)
{
if (New.MACD.Index == At)
return false;
if ((L.MACD.Value > New.MACD.Value && MACD_Is_Min(P: New.MACD, At: At)) || (L.MS.Value > New.MS.Value && MS_Is_Min(P: New.MS, At: At)))
return true;
return false;
}
/// Next Wave
private bool Is_Next_High_Wave(Label A, Label B, int At)
{
bool Was_Lower = MACD_Was_Lower(From: A.MACD.Index, To: B.MACD.Index);
bool B_MACD_Max = MACD_Is_Max(P: B.MACD, At: At);
bool B_MS_Max = MS_Is_Max(P: B.MS, At: At);
bool T1 = A.MACD.Value > 0 && B.MACD.Value > 0 && Was_Lower && B_MACD_Max && B_MS_Max;
bool T2 = A.MACD.Value < 0 && B.MACD.Value > 0 && Was_Lower && B_MACD_Max && B_MS_Max;
bool T3 = A.MACD.Value > 0 && B.MACD.Value < 0 && A.MS.Value < B.MS.Value && B_MS_Max && MACD(Index: B.MS.Index) < 0;
return (T1 || T2 || T3);
}
private bool Is_Next_Low_Wave(Label A, Label B, int At)
{
bool Was_Higher = MACD_Was_Higher(From: A.MACD.Index, To: B.MACD.Index);
bool B_MACD_Min = MACD_Is_Min(P: B.MACD, At: At);
bool B_MS_Min = MS_Is_Min(P: B.MS, At: At);
bool T1 = A.MACD.Value < 0 && B.MACD.Value < 0 && Was_Higher && B_MACD_Min && B_MS_Min;
bool T2 = A.MACD.Value > 0 && B.MACD.Value < 0 && Was_Higher && B_MACD_Min && B_MS_Min;
bool T3 = A.MACD.Value < 0 && B.MACD.Value > 0 && A.MS.Value > B.MS.Value && B_MS_Min && MACD(Index: B.MS.Index) > 0;
return (T1 || T2 || T3);
}
/// Нет препятсвий
private bool No_Obstacles(Divergence D)
{
bool T_MACD = D.T == HIGH ? MACD_Was_Not_Higher(D: D) : MACD_Was_Not_Lower(D: D);
bool T_MS = D.T == HIGH ? MS_Was_Not_Higher(D: D) : MS_Was_Not_Lower(D: D);
//Info(Stage: string.Format("No O: MACD = {0} MS = {1}", T_MACD, T_MS), D: D, At: D.B.MACD.Index);
return (T_MACD && T_MS);
}
/// MS Not higher or lower than
private bool MACD_Was_Not_Higher(Divergence D)
{
return MACD_Was_Not_Higher(From: D.A.MACD.Index, To: D.B.MACD.Index, Value: Math.Max(D.A.MACD.Value, D.B.MACD.Value));
}
private bool MACD_Was_Not_Lower(Divergence D)
{
return MACD_Was_Not_Lower(From: D.A.MACD.Index, To: D.B.MACD.Index, Value: Math.Min(D.A.MACD.Value, D.B.MACD.Value));
}
private bool MACD_Was_Not_Higher(int From, int To, double Value)
{
if (From + 1 > To)
return false;
for (int Index = From + 1; Index < To; Index++)
if (MACD(Index) > Value)
return false;
return true;
}
private bool MACD_Was_Not_Lower(int From, int To, double Value)
{
if (From + 1 > To)
return false;
for (int Index = From + 1; Index < To; Index++)
if (MACD(Index) < Value)
return false;
return true;
}
/// MACD: was lower or higher 2 points
private bool MACD_Was_Lower_Zero(int From, int To)
{
if (From > To)
return false;
for (int Index = From + 1; Index < To; Index++)
if (MACD(Index) < 0)
return true;
return false;
}
private bool MACD_Was_Lower(int From, int To)
{
if (From + 1 > To)
return false;
double From_Value = MACD(From);
double To_Value = MACD(To);
for (int Index = From + 1; Index < To; Index++)
if (MACD(Index) < From_Value && MACD(Index) < To_Value)
return true;
return false;
}
/// MACD: was higher or lower 0
private bool MACD_Was_Higher_Zero(int From, int To)
{
if (From > To)
return false;
for (int Index = From + 1; Index < To; Index++)
if (MACD(Index) > 0)
return true;
return false;
}
private bool MACD_Was_Higher(int From, int To)
{
if (From + 1 > To)
return false;
double From_Value = MACD(From);
double To_Value = MACD(To);
for (int Index = From + 1; Index < To; Index++)
if (MACD(Index) > From_Value && MACD(Index) > To_Value)
return true;
return false;
}
// MS: high & low
private double MS_High(int Index)
{
return Divergence_Extremums ? MarketSeries.High[Index] : MarketSeries.Close[Index];
}
private double MS_Low(int Index)
{
return Divergence_Extremums ? MarketSeries.Low[Index] : MarketSeries.Close[Index];
}
/// MS Not higher or lower than
private bool MS_Was_Not_Higher(Divergence D)
{
return MS_Was_Not_Higher(From: D.A.MS.Index, To: D.B.MS.Index, Value: Math.Max(D.A.MS.Value, D.B.MS.Value));
}
private bool MS_Was_Not_Lower(Divergence D)
{
return MS_Was_Not_Lower(From: D.A.MS.Index, To: D.B.MS.Index, Value: Math.Min(D.A.MS.Value, D.B.MS.Value));
}
private bool MS_Was_Not_Higher(int From, int To, double Value)
{
if (From + 1 > To)
return false;
for (int Index = From + 1; Index < To; Index++)
if (MS_High(Index) > Value)
return false;
return true;
}
private bool MS_Was_Not_Lower(int From, int To, double Value)
{
if (From + 1 > To)
return false;
for (int Index = From + 1; Index < To; Index++)
if (MS_Low(Index) < Value)
return false;
return true;
}
/// MS: max & min points
private Point Max_MS(int From, int For_Last_Bars)
{
int Index = From;
double Value = MS_High(Index);
for (int Bar = 1; Bar <= For_Last_Bars; Bar++)
{
int New_Index = From - Bar;
double New_Value = MS_High(New_Index);
if (New_Value > Value)
{
Value = New_Value;
Index = New_Index;
}
}
return new Point(Index, Value);
}
private Point Min_MS(int From, int For_Last_Bars)
{
int Index = From;
double Value = MS_Low(Index);
for (int Bar = 1; Bar <= For_Last_Bars; Bar++)
{
int New_Index = From - Bar;
double New_Value = MS_Low(New_Index);
if (New_Value < Value)
{
Value = New_Value;
Index = New_Index;
}
}
return new Point(Index, Value);
}
/// MACD: max & min points
private Point Max_MACD(int From, int For_Last_Bars)
{
int Index = From;
double Value = MACD(Index);
for (int Bar = 1; Bar <= For_Last_Bars; Bar++)
{
int New_Index = From - Bar;
double New_Value = MACD(New_Index);
if (New_Value < 0)
return new Point(Index, Value);
if (New_Value > Value)
{
Value = New_Value;
Index = New_Index;
}
}
return new Point(Index, Value);
}
private Point Min_MACD(int From, int For_Last_Bars)
{
int Index = From;
double Value = MACD(Index);
for (int Bar = 1; Bar <= For_Last_Bars; Bar++)
{
int New_Index = From - Bar;
double New_Value = MACD(New_Index);
if (New_Value > 0)
return new Point(Index, Value);
if (New_Value < Value)
{
Value = New_Value;
Index = New_Index;
}
}
return new Point(Index, Value);
}
}
}
@daniel.agg
daniel.agg
07 Mar 2019, 21:51
Sorry, seems like the link to the source code is broken. Reuploaded:
https://drive.google.com/file/d/1CuMe7hKGLAK3XJW0HDQ9RucmDDiEps0S/view?usp=sharing
@daniel.agg
daniel.agg
26 Mar 2019, 18:09
Hi, the problem is solved (using a different indicator). Can you please delete this post?
Thanks in advance,
Dan
@daniel.agg