using System;
using System.Linq;
using System.Threading;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Correlationwithanglev11 : Indicator
    {
        [Parameter("Symbol Selection Method", DefaultValue = SymbolSelectionMethodType.SymbolList, Group = "Symbole Choice \n(Uncomment code for more than 6 Symbole)")]
        public SymbolSelectionMethodType SymbolSelectionMethod { get; set; }
        public enum SymbolSelectionMethodType
        {
            WatchList,
            SymbolList
        }

        [Parameter("Symbol List 1 / WatchList Name 1:", DefaultValue = "XAUUSD", Group = "Symbol Management (5 Symbol / List Maximum)")]
        public string TradedSymbols1 { get; set; }
        [Parameter("Symbol List 2 / WatchList Name 2:", DefaultValue = "SpotBrent", Group = "Symbol Management (5 Symbol / List Maximum)")]
        public string TradedSymbols2 { get; set; }

        [Parameter("ExtraLevel", DefaultValue = 50, Group = "Angle Level")]
        public int ExtraLevel { get; set; }

        [Parameter("PeriodA ngle", DefaultValue = 14, Group = "Angle Setting")]
        public int PeriodAngle { get; set; }
        [Parameter("Loockback Periods Angle", DefaultValue = 1, Group = "Angle Setting")]
        public int LookbackAngle { get; set; }
        [Parameter("Price Smooth Type", DefaultValue = MovingAverageType.Weighted, Group = "Angle Setting")]
        public MovingAverageType MaTypeAngle { get; set; }

        [Parameter("History Diff Angle", DefaultValue = 1, Group = "Base Setting")]
        public int HistoryTextLookback { get; set; }

        [Parameter("ShowSignals", DefaultValue = true, Group = "Histogram Setting")]
        public bool ShowSignal { get; set; }
        [Parameter("Sensibility Histogram", DefaultValue = 0.3, Group = "Histogram Setting")]
        public double SensibilityHisto { get; set; }

        [Parameter("Signal Periods", DefaultValue = 55, Group = "Histogram Setting")]
        public int SignalPeriods { get; set; }
        [Parameter("Price Smooth Type", DefaultValue = MovingAverageType.Weighted, Group = "Histogram Setting")]
        public MovingAverageType MaTypeSignal { get; set; }

        [Output("List 1 : Symb n° 1", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries SymbN1 { get; set; }
        [Output("List 1 : Symb n° 2", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries SymbN2 { get; set; }
        [Output("List 1 : Symb n° 3", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries SymbN3 { get; set; }
        [Output("List 1 : Symb n° 4", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries SymbN4 { get; set; }
        [Output("List 1 : Symb n° 5", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries SymbN5 { get; set; }

        [Output("List 2 : Symb n° 6", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries SymbN6 { get; set; }
        [Output("List 2 : Symb n° 7", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries SymbN7 { get; set; }
        [Output("List 2 : Symb n° 8", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries SymbN8 { get; set; }
        [Output("List 2 : Symb n° 9", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries SymbN9 { get; set; }
        [Output("List 2 : Symb n° 10", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries SymbN10 { get; set; }

        [Output("LevelHigh", LineColor = "Gold", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries LevelHigh { get; set; }
        [Output("LevelMid", LineColor = "White", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries LevelMid { get; set; }
        [Output("LevelLow", LineColor = "Gold", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)]
        public IndicatorDataSeries LevelLow { get; set; }

        private MovingAverage[] angleIndex1, angleIndex2;
        private AverageTrueRange[] atrIndex1, atrIndex2;

        private Symbol[] TradeList1, TradeList2;
        private Bars[] bars1, bars2;
        private IndicatorDataSeries[] ResPaireWatchlist1, ResPaireWatchlist2;
        private int[] indexBars1, indexBars2;

        protected override void Initialize()
        {
            if (SymbolSelectionMethod == SymbolSelectionMethodType.WatchList)
            {
                // Get the trade list from the watchlist 1 provided by the user
                foreach (Watchlist w in Watchlists)
                {
                    if (w.Name == TradedSymbols1)
                    {
                        TradeList1 = Symbols.GetSymbols(w.SymbolNames.ToArray());
                    }
                }
                // Get the trade list from the watchlist 2 provided by the user
                foreach (Watchlist w in Watchlists)
                {
                    if (w.Name == TradedSymbols2)
                    {
                        TradeList2 = Symbols.GetSymbols(w.SymbolNames.ToArray());
                    }
                }
                Print();
                Print("Watchlist 1 : [ {0} ] = {1} symbols   ||   Watchlist 2 : [ {2} ] = {3} symbols", Bars.ToString().Substring(0, 3), TradeList1.Length, Bars.ToString().Substring(3, 3), TradeList2.Length);
                Print();
            }
            else if (SymbolSelectionMethod == SymbolSelectionMethodType.SymbolList)
            {
                // Get the trade list from the SymbolList provided by the user
                string[] SymbolList = TradedSymbols1.Split(' ');
                TradeList1 = Symbols.GetSymbols(SymbolList);

                // Get the trade list from the SymbolList provided by the user
                string[] SymbolList2 = TradedSymbols2.Split(' ');
                TradeList2 = Symbols.GetSymbols(SymbolList2);
            }

            //Create Indicators for Watchlist 1
            angleIndex1 = new MovingAverage[TradeList1.Length];
            atrIndex1 = new AverageTrueRange[TradeList1.Length];
            bars1 = new Bars[TradeList1.Length];
            indexBars1 = new int[TradeList1.Length];
            ResPaireWatchlist1 = new IndicatorDataSeries[TradeList1.Length];

            //Create Indicators for Watchlist 2
            angleIndex2 = new MovingAverage[TradeList2.Length];
            atrIndex2 = new AverageTrueRange[TradeList2.Length];
            bars2 = new Bars[TradeList2.Length];
            indexBars2 = new int[TradeList2.Length];
            ResPaireWatchlist2 = new IndicatorDataSeries[TradeList2.Length];

            //Initialize Indicators for Watchlist 1
            int i = 0;
            foreach (var symbol in TradeList1)
            {
                Print("Watchlist : [ {0} ] => {1} symbols = {2}", Bars.SymbolName, (i + 1), symbol.Name);
                //Load bars of watchlist 1
                bars1[i] = MarketData.GetBars(TimeFrame, symbol.Name);
                while (bars1[i].OpenTimes[0] > Bars.OpenTimes[0])
                    bars1[i].LoadMoreHistory();

                //Load Futurs DataSerie watchlist 1 (calculation in Calculate(int index))
                ResPaireWatchlist1[i] = CreateDataSeries();

                //Load Indicators watchlist 1

                atrIndex1[i] = Indicators.AverageTrueRange(bars1[i], 500, MovingAverageType.Simple);
                angleIndex1[i] = Indicators.MovingAverage(bars1[i].ClosePrices, PeriodAngle, MaTypeAngle);
                i++;
            }
            //Initialize Indicators for Watchlist 2
            Print();

            int j = 0;
            foreach (var symbol2 in TradeList2)
            {
                Print("Watchlist : [ {0} ] => {1} symbols = {2}", Bars.SymbolName, (j + 1), symbol2.Name);
                //Load bars of watchlist 2
                bars2[j] = MarketData.GetBars(TimeFrame, symbol2.Name);
                while (bars2[j].OpenTimes[0] > Bars.OpenTimes[0])
                    bars2[j].LoadMoreHistory();

                //Load Futurs DataSerie watchlist 2 (calculation in Calculate(int index))
                ResPaireWatchlist2[j] = CreateDataSeries();

                //Load Indicators watchlist 2
                atrIndex2[j] = Indicators.AverageTrueRange(bars2[j], 500, MovingAverageType.Simple);
                angleIndex2[j] = Indicators.MovingAverage(bars2[j].ClosePrices, PeriodAngle, MaTypeAngle);
                j++;
            }
            Print();
        }
        public override void Calculate(int index)
        {
            //Plot Static level on indicator
            LevelHigh[index] = ExtraLevel;
            LevelMid[index] = 0;
            LevelLow[index] = 0 - ExtraLevel;

            if (index < PeriodAngle)
                return;

            //Calculate angle by symbol list 1
            for (int i = 0; i < TradeList1.Length; i++)
            {
                indexBars1[i] = bars1[i].OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
                ResPaireWatchlist1[i][index] = GetCalculationAngle(angleIndex1[i].Result[indexBars1[i]], angleIndex1[i].Result[indexBars1[i] - LookbackAngle], atrIndex1[i].Result[indexBars1[i]]);
            }

            //Remove Static text of difference into index and index - HistoryTextLookback
            if (IndicatorArea.FindAllObjects(ChartObjectType.Text).Length > 0)
                IndicatorArea.RemoveAllObjects();
            //Calculate difference into index and index - HistoryTextLookback list 1
            for (int i = 0; i < TradeList1.Length; i++)
                IndicatorArea.DrawText((TradeList1[i]).ToString() + index, TradeList1[i] + " : " + ResPaireWatchlist1[i][index].ToString("F2"), index + 2, double.IsNaN(ResPaireWatchlist1[i][index]) ? 0 : ResPaireWatchlist1[i][index], ResPaireWatchlist1[i][index] > ResPaireWatchlist1[i][index - HistoryTextLookback] ? Color.Lime : Color.Red);

            //Output the result like symbolList number != output number list 1
            int j = TradeList1.Length - 1;
            SymbN1[index] = ResPaireWatchlist1[0 < j ? 0 : j][index];
            SymbN2[index] = ResPaireWatchlist1[1 < j ? 1 : j][index];
            SymbN3[index] = ResPaireWatchlist1[2 < j ? 2 : j][index];
            SymbN4[index] = ResPaireWatchlist1[3 < j ? 3 : j][index];
            SymbN5[index] = ResPaireWatchlist1[4 < j ? 4 : j][index];

            //Calculate angle by symbol list 2
            for (int i = 0; i < TradeList2.Length; i++)
            {
                indexBars2[i] = bars2[i].OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
                ResPaireWatchlist2[i][index] = GetCalculationAngle(angleIndex2[i].Result[indexBars2[i]], angleIndex2[i].Result[indexBars2[i] - LookbackAngle], atrIndex2[i].Result[indexBars2[i]]);
            }

            //Calculate difference into index and index - HistoryTextLookback list 2
            for (int i = 0; i < TradeList2.Length; i++)
                IndicatorArea.DrawText((TradeList2[i]).ToString() + index, TradeList2[i] + " : " + ResPaireWatchlist2[i][index].ToString("F2"), index + 2, double.IsNaN(ResPaireWatchlist2[i][index]) ? 0 : ResPaireWatchlist2[i][index], ResPaireWatchlist2[i][index] > ResPaireWatchlist2[i][index - HistoryTextLookback] ? Color.Lime : Color.Red);

            //Output the result like symbolList number != output number list 2
            int k = TradeList2.Length - 1;
            SymbN6[index] = ResPaireWatchlist2[0 < k ? 0 : k][index];
            SymbN7[index] = ResPaireWatchlist2[1 < k ? 1 : k][index];
            SymbN8[index] = ResPaireWatchlist2[2 < k ? 2 : k][index];
            SymbN9[index] = ResPaireWatchlist2[3 < k ? 3 : k][index];
            SymbN10[index] = ResPaireWatchlist2[4 < k ? 4 : k][index];

        }

        //Function for angle calculation with atr normalization
        public double GetCalculationAngle(double priceSmooth, double priceSmoothLoockBack, double atr)
        {
            var _momentumpositive = priceSmooth - priceSmoothLoockBack;
            var _momentumnegative = priceSmoothLoockBack - priceSmooth;
            var _momentum = priceSmooth > priceSmoothLoockBack
                         ? _momentumpositive / atr
                         : _momentumnegative / atr;
            var _hypothenuse = Math.Sqrt((_momentum * _momentum) + (LookbackAngle * LookbackAngle));
            var _cos = (LookbackAngle / _hypothenuse);
            var _angle = priceSmooth > priceSmoothLoockBack
                         ? (0 + (Math.Acos(_cos) * 100))
                         : (0 - (Math.Acos(_cos) * 100));
            return _angle;
        }
    }
}
