locked
checking elements in a List RRS feed

  • Question

  • Hello,

    I am trying to find the closest number in a list. But the lambda always return the last element of the list and not the number of my variable fibo2.

    double newvol =	sumvolms / sumvols;
                            
    										
    List<double> zlist = new List<double>() {newvol};
    
    double minDistance = list.Min(no => Math.Abs(fibo2- no));
    						
    double closest = list.First(no => Math.Abs(fibo2- no) == minDistance);
    										
    
    											
    	
    //if list return 1, 2, 3 and fibo2 = 1, the lambda return 3. It should return 1.
    									

    Any idea why it does that?

    Thank you

    Wednesday, August 26, 2020 1:15 PM

Answers

  • Good morning Cool,

    You are right by moving aggregate calculation outside of brackets it return the closest for each cma's.

    Problem solve! Thank you for all your help. I am closer from finishing this project.

    Thank you also to Karen.

    • Marked as answer by Frankdot Friday, August 28, 2020 12:46 PM
    Friday, August 28, 2020 12:46 PM

All replies

  • Try this

    static void Main(string[] args)
    {
        var list = new List<double> { 2.5, 5, 7.6, 1, 10 };
        var number = 6.7;
    
        double closest = list.Aggregate((x, y) => Math.Abs(x - number) < Math.Abs(y - number) ? x : y);
        Console.WriteLine(closest);
        Console.ReadLine();
    }
    

    https://stackoverflow.com/questions/5953552/how-to-get-the-closest-number-from-a-listint-with-linq


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Wednesday, August 26, 2020 1:46 PM
  • Karen,

    I get the same return than my solution.

    Its more like it test individually each number in the list instead of testing the closest for all the list.

    The problem is not the lambda but how it process the list.

    For example, it return 2.5,

                                    closest 2.5,

                                    5,

                                          closest 5

    etc

    Wednesday, August 26, 2020 2:03 PM
  • It is unclear to me what you define as closest but it sounds like you want the first number that is as close to `fibo2` as possible. In your example code you are first finding the smallest difference in the list. Then you enumerate the list again looking for a value with that distance. Given your example the first value (1) is the closest because there is no difference. 

    var items = new[] { 1, 2, 3 };
    var fibo = 1;
    
    var groupedData = from i in items
                      let distance = Math.Abs(fibo - i)
                      select new { Value = i, Distance = distance };
    
    //Have all the values and their distances so now we can aggregate
    var closest = groupedData.OrderBy(x => x.Distance).FirstOrDefault();

    If, for example, you used (40, 45, 50) and a fibo of 42 then the answer would be 40.

    If we are missing something on your algorithm then please provide a more concrete example that doesn't have duplicate values like 1 and 1 along with a clarification of what is different.


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, August 26, 2020 3:14 PM
  • Karen,

    I get the same return than my solution.

    Its more like it test individually each number in the list instead of testing the closest for all the list.

    The problem is not the lambda but how it process the list.

    For example, it return 2.5,

                                    closest 2.5,

                                    5,

                                          closest 5

    etc

    Can't help if you don't post a decent code sample as I don't understand this reply of yours without code to back it up.

    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Wednesday, August 26, 2020 3:23 PM
  • Hello Cool,

    closests{ Value = 0,369240654725541, Distance = 1,13573373429725 }
    zlist0,369240654725541


    closests{ Value = 0,377390750985181, Distance = 1,12934232750952 }
    zlist0,377390750985181but closest return 

    If i try all solutions with an array and ask the closest from 42 in (40,45,50) it will return 40.

    But its a list. In the list are included 0,369240654725541 and 0,377390750985181.

    Wednesday, August 26, 2020 3:28 PM
  • I don't understand your fixation on the list. The list is the series of values you want to scan through. If you're looking for the closest value then you'll generally get 1 value, not a list. The only time you might get back more than 1 is if you had multiple values with the exact same distance. 

    In your example you've suddenly added in some completely unknown value zlist. What does this have to do with anything. In your example you seem to be showing some results. Please post the original list you got this from and your fib0 value from the original code that produces the results. Then explain what exactly you are expecting in the results. I cannot figure out in your post how the 2 different sets of closets values related to zlist or your final comment about "in the list". Please update the code I or Karen posted to include your exact sample list you're running against, the result you're getting and what you really expect.  It would also be useful to understand why you'd expect multiple results back.


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, August 26, 2020 3:37 PM
  •  double newvol =sumvolms / sumvols;
       //newvol return numbers                     
    						
    List<double> zlist = new List<double>() {newvol};
    
    //in the list you got the numbers	
    						
    double closests = zlist.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    					
    //the lambda is suppose to return closest number from fibo2
    			
    Print("closests"+closests);
    
    
    Print("new"+newvol);
    //but the lambda return same numbers as newvol or zlist.
    
    // zlist or newvol return 0.36, 0.37 
    and closest also return 0.36,0.37 
    // if fibo2 = 0.25 closest should return 0.36 but its not the case. 
    

    Wednesday, August 26, 2020 3:59 PM
  •  double newvol =sumvolms / sumvols;
       //newvol return numbers                     
    						
    List<double> zlist = new List<double>() {newvol};
    
    //in the list you got the numbers	
    						
    double closests = zlist.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    					
    //the lambda is suppose to return closest number from fibo2
    			
    Print("closests"+closests);
    
    
    Print("new"+newvol);
    //but the lambda return same numbers as newvol or zlist.
    
    // zlist or newvol return 0.36, 0.37 
    and closest also return 0.36,0.37 
    // if fibo2 = 0.25 closest should return 0.36 but its not the case. 

    I beleive it is related to the format of the numbers coming out of newvol. The numbers maybe need to be seperated by commas. That would explain why in array or list the lambda cant be applied.
    Wednesday, August 26, 2020 7:13 PM
  • Not sure what you mean by the format of `newvol`. It's a double so it only has 1 value. You are putting that into a list which would only ever have a single value. Not really sure why you're doing that at all. 

    After you put the only value you'll ever have in that list you're then aggregating it which produces a single value. That code is equivalent to this.

    double newvol =sumvolms / sumvols;
    
    double closests = Math.Abs(newvol - fibo2) < Math.Abs(y-fibo2) ? newvol : fibo2;
    					
    The above code is going to set `closests`to 0 because it doesn't enumerate the first value and hence it would be the default of 0. Aggregate is used to use previous values to produce future values and ultimately return a single value. Common aggregates for which there are specialized methods provided include Sum, Min and Max. In your case I cannot see a benefit for you using this especially since you keep talking about `closests` being a list and Aggregate never returns more than one value.

    So I'm going back to what I originally posted, `closests` is going to return a single value back. If you want more than 1 value then Aggregate isn't the correct method to use. To get the value in the list `zlist` (which has only 1 value in your case) that is closest to `fibo2` then the original LINQ I posted does exactly that. It would produce the same exact value as Aggregate if you had more than 1 item in the list.

    So, again, why do you keep expecting multiple values from Aggregate? Is `newvols` really a single value or are you just simplifying it for our benefit. Please provide the exact code you're trying to use as the typing is important. For each step of the code please provide the exact value you expect to see in each variable so we can understand where you're going with this.


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, August 26, 2020 7:29 PM
  • for(int barIndex = foundIndex; barIndex <= ChartBars.ToIndex; barIndex++) { closePrice = Bars.GetClose(barIndex); //closePrice return in the output window all prices: 10 12 15 27 but they are not seperated by commas. double[] array3 = new double [] {closePrice}; // usually in an array you would have {10,12,15,27} double CW = array3.Aggregate((x, y) => Math.Abs(x - 17) < Math.Abs(y - 17) ? x : y); // if i try with double[] array3 = new double [] {10,12,15,27} it will return 15 but not if i replace the

    numbers seperated by commas by closePrice variable. }

    You understand now my problem?
    Wednesday, August 26, 2020 7:47 PM
  • If separated by space and sure each element is a valid double or int.

    var line = "10 12 15 27";
    double[] values = line
        .Split(' ')
        .Select(double.Parse)
        .ToArray();


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Wednesday, August 26, 2020 8:00 PM
  • What you're saying cannot compile. Let's take this apart.

    `closePrice` what is its type? If it is a string AND you have a series of values like "10 20 30" then you can convert it like Karen mentioned. But that line where you put it into a double array would fail to compile.

    I suspect it is returning a single double value. But you're storing it into a single double variable so of course you cannot fit multiple values there. If `closePrice` is a double and you want it for each index then convert it to an array directly.

    var closePrices = new List<double>();
    for(int barIndex = foundIndex; barIndex <= ChartBars.ToIndex; barIndex++)
       closePrices.Add(Bars.GetClose(barIndex));
    
    //Now aggregate but this will still return a single value
    double CW = closePrices.Aggregate(...);


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, August 26, 2020 8:57 PM
  • Yes closePrice is a double variable.

    Yes i cannot fit multiple values as a single double variable in an array or a list.

    The return is the last double value of closePrice serie of values. 

    What (...) is standing for ? 

    I get a message error: No overload for the 'Aggregate' method takes 0 arguments.

    Can we convert it to a list?

    Thursday, August 27, 2020 12:31 PM
  • The `(...)` means the code you originally had for that method call. Didn't want to type it back out.

    The code I posted gets the result of `GetClose` for each of your bars and stores in a list. Then it will run the Aggregate function against all those values looking for the one that is closest based upon the function you gave it. This is an aggregate so the result is a single value (just like sum or min or max).

    If you want a list then a list of what? Aggregation always returns a single value. If you are expecting more than one then you'd use Where but that requires you filter on the results so I'm not sure how finding the closest would work.


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, August 27, 2020 3:04 PM
  • Your solution works with closePrices.

    Now i tried to apply it to my previous example.

    double newvol =	sumvolms / sumvols;
                            
    							
    var newvols = new List<double>();
    							
    					
    newvols.Add(sumvolms / sumvols);
    																
    						
    double CWW = newvols.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    								
    				
    Print("closests"+CWW);
    				
    Print("new"+newvol);

    Here's the return in the Output window:

    ar146 // 146 is cumulative average 146, there is 146 cma's 

    3cma2988,35947180285       // CMA return for cma 146
    closests26,8821440307754    // closest number from fibo 1.52
    new26,8821440307754        // result from newvol
    closests27,4052545911765
    new27,4052545911765
    closests28,0942263545574
    new28,0942263545574
    closests34,0940283803263
    new34,0940283803263
    closests34,7848991554104
    new34,7848991554104
    closests35,4766060450142
    new35,4766060450142
    closests41,4876393398581
    new41,4876393398581

    ar0  // cma 0 and it goes on from 0 to 146
    2fibo1,52750456834921
    3cma3025,06128448763
    closests0,371684503902004
    new0,371684503902004
    1nearclose3548,3337872151
    closests0,379888542233778
    new0,379888542233778
    1nearclose3537,3882636475
    closests0,389625539001297
    new0,389625539001297
    1nearclose3524,62166009722
    closests0,395139967652765
    new0,395139967652765
    1nearclose3517,49693687547
    closests0,451061433927214
    new0,451061433927214

    Is it possible its not working for this particular case because there is an index that create multiple cma's? The nested for loop prevent the lambda from finding closest in the list?

    By the way sumvolms and sumvols are coming from :

    for(int barIndex = index; barIndex <= ChartBars.ToIndex; barIndex++)
                    {
    			 
    double vols =  Bars.GetVolume(barIndex);
    				
    				
     sumvolms += vols;
    
                    }
    		
    
    
    for(int barIndex = item; barIndex <= index; barIndex++)
    		{
    				
    double volumes = Bars.GetVolume(barIndex);	
    				
    				
    sumvols += volumes;				
    
                     }

    Thank you


    • Edited by Frankdot Thursday, August 27, 2020 5:17 PM
    Thursday, August 27, 2020 4:54 PM
  • You keep going back to the same solution that I said was wrong. So let me repeat this again you CANNOT use a list of 1 item AND an aggregate method. It does not make sense. Aggregate only applies when dealing with more than 1 value. There is never a case where you would do this. That is the mistake you keep making and why things aren't working. As soon as you stop trying to do that you will start getting the results you expect.  Let me explain.

    Given your code `CWW` and `newvol` will be the same in this case. Aggregate works by skipping the first item and then applying your function to each subsequent value. Since you have a single item in the list the return value is always the first item in the list. Since your list contained `newvol` that will be the result stored in `CWW`. Hence they are always the same. There is no way around this as you only have 1 item in the list. This will never work out for you.

    You've thrown new terminology into the discussion without any explanation so we cannot follow what these cma things are that you're suddenly talking about. I also don't see how this correlates to the foreach you posted earlier so let's reset the discussion for a minute. You said the previous code that I posted works. So we can assume we are past the initial problem. Now we need to understand where these CMA values are coming from and what they are and how that relates to your bars. It looks like this code is part of a larger method. Does that method have the other looping you're talking about? Can you please post the entire method this code is running in so we can see the big picture? If that method relies on any fields outside the class then please post the definition of those fields as well. From that we should be able to show you how to enumerate to get the results you want.


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, August 27, 2020 5:17 PM
  • Here's most of the code:

      int totalI = 0;
    
    for(int barIndex0 = ChartBars.FromIndex; barIndex0 <= index; barIndex0++)
    	{
    	totalI = barIndex0;
    					
    					
    					 
    					 
    List<int> sumlist = new List<int>() {totalI};
    				  
    				
    
    foreach(var item in sumlist) //create multiple cma's
    	{
    		Print("ar"+item);
    				 
    double closePrice3 = 0;
    double volumes3 = 0;
    double sum4 = 0;
    double sum5 = 0;
    double cma3 = 0;
    				  
    for(int barIndex = item; barIndex <= ChartBars.ToIndex; barIndex++)
    		{
    	closePrice3 = Bars.GetClose(barIndex);
    	volumes3 = Bars.GetVolume(barIndex);	
    					
    double clovol3 = closePrice3 * volumes3;	
    					
    					
    sum4 += clovol3++;
    sum5 += volumes3++;
    				
    cma3 = sum4 / sum5;
    					
    				
    		}	
    				
    					
    			 	
    					
    				
    double fibo2 = (Close.GetValueAt(CurrentBar) - lowPrice0) / (cma3 - lowPrice0);	
    				
    	Print("2fibo" + fibo2);
    				
    	Print("3cma"+cma3);	
    					
    			 	
    
    //CMA 
    double sum =0;
    int barIndex1 = 0;
    double sumOfVolumesx = 0;
    int counter = 0;
    double sumvols = 0;
    				
    for(int barIndex = item; barIndex <= index; barIndex++)
    	{
    
    double closePrice = Bars.GetClose(barIndex);
    double volumes = Bars.GetVolume(barIndex);	
    				
    double vols =  closePrice * volumes;
    					
    	sumvols += volumes;	// this is sumvols
    	sum += vols;
    					
    				
    				
    double cma1 = sum / sumvols;
    					
    				
    				
                 
    if(closePrice > cma1)
    	{ 
    
    	counter++;
    
    sumOfVolumesx += Bars.GetVolume(barIndex);
    					
    		}
    	
    		}
    				
    				
      double sumvolms = 0;
    				
    for(int barIndex = index; barIndex <= ChartBars.ToIndex; barIndex++)
                    {    
    
    double highPrice = Bars.GetHigh(barIndex);
    double lowPrice = Bars.GetLow(barIndex);	
    double vols =  Bars.GetVolume(barIndex); 
    double Price = Bars.GetClose(barIndex);	
    				
    				
    					
     sumvolms += vols; // sumvolms is sum of volume in for loop
    					
    				
    if(cma3 < highPrice && cma3 > lowPrice)
    		{		
    								
    					
    											
    //total0										
                              
    						   
       double newvol =	sumvolms / sumvols;
                            
    							
    var newvols = new List<double>();
    										
    								
    								
    				
    newvols.Add(sumvolms / sumvols);
    						
    double CWW = newvols.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    
    //you cant aggregate from what you said but at this point i dont get it. I am an amateur programmer if you did'nt guess
    		
    foreach (double item1 in newvols)
            						
    {
    					
    Print("new"+item1);									
    							
    }	
    
    }
    }
    }								
    											

    Thursday, August 27, 2020 5:33 PM
  • OK I'm going to do this in multiple passes. In the first pass I've annotated your existing code with NOTE: to identify either questions or comments about your code. Ultimately I think the fact you're enumerating your bars over and over again is making this far harder than it needs to be. 

    static void DoWork ()
    {
        //NOTE: The following variables are referenced in this code but the definitions are not provided
        // ChartBars, Close, CurrentBar, lowPrice0, Bars, index
        //making up the values
        Bar ChartBars = new Bar() { FromIndex = 0, ToIndex = 5 };
        Close Close = new Close();
        Bar Bars = new Bar();
        double lowPrice0 = 100;  //Note: currency should use decimal, not double
        Bar CurrentBar = new Bar();
        int index = ChartBars.ToIndex;
    
        //int totalI = 0;
    
        for (int barIndex0 = ChartBars.FromIndex; barIndex0 <= index; barIndex0++)
        {
            //totalI = barIndex0;
            //List<int> sumlist = new List<int>() { totalI };
    
            //NOTE: Looping through a list of 1 item is the same as having no loop at all
            //foreach (var item in sumlist) //create multiple cma's
            //{
                //NOTE: item = sumlist[0] = totalI = barIndex0, adding temp variable so remainder of code is unchanged
                int item = barIndex0;
                Print("ar "+item);
    
                //NOTE: Moving these inside loop so they aren't misused
                //double closePrice3 = 0;
                //double volumes3 = 0;
                double sum4 = 0;
                double sum5 = 0;
                double cma3 = 0;
    
                //NOTE: This will enumerate all the bars from the current bar to end
                //Example: first time through outer loop it'll be FromIndex to ToIndex
                //  second time through outer loop it'll be FromIndex + 1 to ToIndex
                //Don't know if this is correct for your algorithm but the result is a single cma3 value based
                //upon the calculations for the enumerated bars
                for (int barIndex = item; barIndex <= ChartBars.ToIndex; barIndex++)
                {
                    double closePrice3 = Bars.GetClose(barIndex);
                    double volumes3 = Bars.GetVolume(barIndex);
    
                    double clovol3 = closePrice3 * volumes3;
    
                    sum4 += clovol3++;
                    sum5 += volumes3++;
    
                    cma3 = sum4 / sum5;
                }
    
                double fibo2 = (Close.GetValueAt(CurrentBar) - lowPrice0) / (cma3 - lowPrice0);
                Print("2fibo: " + fibo2);
                Print("3cma: "+cma3);
    
                //CMA 
                double sum = 0;
    
                //NOTE: Not used
                //int barIndex1 = 0;
    
                double sumOfVolumesx = 0;
    
                //NOTE: Does this do anything?
                int counter = 0;
    
                double sumvols = 0;
    
                //NOTE: This loop is identical to previous loop except it uses `index`
                //If index and ChartBars.ToIndex are the same value then all the code in this loop
                //can be moved up into the previous loop and this code removed
                for (int barIndex = item; barIndex <= index; barIndex++)
                {
                    //NOTE: Same as closePrice3 in previous loop
                    double closePrice = Bars.GetClose(barIndex);
                    //NOTE: Same as volumes3 in previous loop
                    double volumes = Bars.GetVolume(barIndex);
    
                    //NOTE: Same as clovol3 in previous loop
                    double vols = closePrice * volumes;
    
                    //NOTE: Same as sum5 in previous loop except other loop adds 1 to it
                    sumvols += volumes; // this is sumvols
    
                    //NOTE: Same as sum4 in previous loop except other loop adds 1 to it
                    sum += vols;
    
                    //NOTE: Same as cma3 except 1 is added to each value each time
                    double cma1 = sum / sumvols;
    
                    if (closePrice > cma1)
                    {
                        counter++;
                        sumOfVolumesx += Bars.GetVolume(barIndex);
                    }
                }
    
                //NOTE: Looping yet again over same values as first loop
                double sumvolms = 0;
                for (int barIndex = index; barIndex <= ChartBars.ToIndex; barIndex++)
                {
                    double highPrice = Bars.GetHigh(barIndex);
                    double lowPrice = Bars.GetLow(barIndex);
    
                    //NOTE: Same as volumes and volumes3
                    double vols = Bars.GetVolume(barIndex);
    
                    //NOTE: Same as closePrice and closePrice3
                    double Price = Bars.GetClose(barIndex);
    
                    //NOTE: Same as sumvols and sum5 (except other loop adds 1)
                    sumvolms += vols; // sumvolms is sum of volume in for loop
    
                    //NOTE: Sure you don't want <= and >= here?
                    if (cma3 < highPrice && cma3 > lowPrice)
                    {
                        //total0										
                        double newvol = sumvolms / sumvols;
                        var newvols = new List<double>();
    
                        newvols.Add(sumvolms / sumvols);
    
                        double CWW = newvols.Aggregate(( x, y ) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    
                        //NOTE: As mentioned in earlier loop, this would only loop once and therefore is not needed
                        //you cant aggregate from what you said but at this point i dont get it. I am an amateur programmer if you did'nt guess
                        foreach (double item1 in newvols)
                        {
                            Print("new"+item1);
                        }
                    }
                }
            //}
        }
    }
    I'm going to make a very big assumption that `index` (which wasn't provided) is the same value as `ChartBars.ToIndex`. If that is true then we can combine the loops into one, add a couple of helper methods and boil down the code to where we can more easily understand it. At that point I think the aggregate will pop up. Is it correct that `index` is set to `ChartBars.ToIndex`? Also is it correct that for each bar you are expecting to get back a cma based upon the aggregate you're using? So if you had 4 bars you'd get back 4 "closest" values?


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, August 27, 2020 6:18 PM
  • I do admit i could clean up the code and remove some things. Sometimes  i try methods and variables and forget to delete them when they are of no use. 

    "index" is very different from `ChartBars.ToIndex`. index refer to a specific bar to begin the loop in the chart and `ChartBars.ToIndex` is the end of the right part of the chart, to the opposite of `ChartBars.FromIndex` which is the beginning of the left part of the chart. 

    There are 2 cma's code, the second calculate a moving average that goes from index to the right side of the chart `ChartBars.ToIndex` and the first cma is calculating the part from item to index. item is every bar from left side of the chart to index.  That cma for loop with item reproduce as many cma as there is bars between left part of the chart and index. Meaning 146 bars = 146 cma's. Each cma return a number of values and the aggregate lambda return the closest value from fibo by cma.

    You cannot combine or merge the 2 cma code otherwise it will change the algorithm. 

    //NOTE: Moving these inside loop so they aren't misused

    Actually, those variables are called as class variables so they can be used in other class with

    other methods.

    I was reading about aggregate  and i am starting to see what you mean.

    But at this point i am still learning how it could work before coming with an idea. I just wish it was possible to apply your solution directly.



    • Edited by Frankdot Thursday, August 27, 2020 6:45 PM
    Thursday, August 27, 2020 6:41 PM
  • I bet we can get this method down to a single loop or 2 at most but give me a little bit to look at it.

    As for the index vs ToIndex that's fine. But I assume index is a parameter to the method so that is how I'll code it.

    But for the note that the vars were moved inside the loop they cannot be class variables as they are declared inside the method body. Therefore they are scoped to the method and not accessible outside it. The only variables that I assumed were fields were the one's at the top that I annotated. The remainder of the variables I did scope analysis and they aren't used outside the loop so they can be moved in. But this will mostly be a mute point after we refactor all that code anyway so we'll see.



    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, August 27, 2020 6:51 PM
  • It took me many trials before i finally get to the answer i was looking for. If you moved a loop lower or outside a field it returns a completely different answer. 

    I already try to reuse double sum4 =0 for example for another loop but the result changed.

    When i mean outside as class variables, i mean outside the code i have publish in the forum. I did not provided all the algorithm. There's enough to my taste online i wont show more for obvious reasons.

    Thursday, August 27, 2020 7:03 PM
  • OK here is a first pass cleanup of the code.

    static List<BarData> GetBarData ( Bar bar, int startIndex, int endIndex )
    {
        var items = new List<BarData>();
    
        //NOTE: If Bar implements IEnumerable<T> then we can reduce this down even further
        for (var index = startIndex; index < endIndex; ++index)
            items.Add(new BarData() {
                ClosePrice = bar.GetClose(index),
                Volume = bar.GetVolume(index),
                HighPrice = bar.GetHigh(index),
                LowPrice = bar.GetLow(index)
            });
    
        return items;
    }
    
    static double GetCma ( List<BarData> bars, int startIndex, int endIndex )
    {
        //Could use aggregate here but that would require 2 enumerations
        double closeSum = 0, volSum = 0;
        for (var index = startIndex; index <= endIndex; ++index)            
        {
            var bar = bars[index];
    
            closeSum += bar.CloseVolume;
            volSum += bar.Volume;
        };
    
        return closeSum / volSum;
    }
    
    static double GetVolumeSum ( List<BarData> bars, int startIndex, int endIndex )
    {
        //NOTE: This is a perfect candidate for Sum but sticking with for loop for consistency            
        double sum = 0;
        for (var index = startIndex; index <= endIndex; ++index)
            sum += bars[index].Volume;
    
        return sum;
    }        
    
    static void DoWork2 ( int index )
    {           
        //NOTE: Helper variables to cut down on complex names
        var fromIndex = ChartBars.FromIndex;
        var toIndex = ChartBars.ToIndex;
    
        //Get the necessary data for all the bars to save calls later
        //NOTE: Assuming index will be <= ToIndex, if not then change last param to index
        List<BarData> bars = GetBarData(Bars, fromIndex, toIndex);
                            
        //NOTE: Prefer foreach here but will stick with for to be consistent
        //Get all the bars from FromIndex up to and including index
        //for (int barIndex0 = ChartBars.FromIndex; barIndex0 <= index; barIndex0++)            
        for (int barIndex = fromIndex; barIndex <= index; ++barIndex)
        {
            //int item = barIndex0;
            Print("ar " + barIndex);
    
            //Get the CMA from current bar to end
            double cma3 = GetCma(bars, barIndex, toIndex);                
            //double sum4 = 0;
            //double sum5 = 0;
            //double cma3 = 0;                
            //for (int barIndex = item; barIndex <= ChartBars.ToIndex; barIndex++)
            //{                    
            //    double closePrice3 = Bars.GetClose(barIndex);
            //    double volumes3 = Bars.GetVolume(barIndex);
    
            //    double clovol3 = closePrice3 * volumes3;
    
            //    //NOTE: This is postfix increment so clovol3 and volumes3 are incremented AFTER they are added
            //    //to the sum but since these are local variables they will get reset each loop so the increment
            //    //has no effect x++ => temp = x; x = x + 1; return temp;
            //    sum4 += clovol3++;
            //    sum5 += volumes3++;
    
            //    cma3 = sum4 / sum5;
            //}
    
            double fibo2 = (Close.GetValueAt(CurrentBar) - lowPrice0) / (cma3 - lowPrice0);
            Print("2fibo: " + fibo2);
            Print("3cma: "+cma3);
    
            double sumvols = GetVolumeSum(bars, barIndex, index);                
            //double sumvols = 0;
            //for (int barIndex = item; barIndex <= index; barIndex++)
            //{
            //    //double closePrice = Bars.GetClose(barIndex);
            //    double volumes = Bars.GetVolume(barIndex);
            //    //double vols = closePrice * volumes;
            //    sumvols += volumes; // this is sumvols
            //    //sum += vols;
            //    //double cma1 = sum / sumvols;
            //    //if (closePrice > cma1)
            //    //{
            //    //    counter++;
            //    //    sumOfVolumesx += Bars.GetVolume(barIndex);
            //    //}
            //}
    
            //Loop through everything after index
            double sumvolms = 0;
            for (int remainingIndex = index; barIndex <= ChartBars.ToIndex; remainingIndex++)
            {
                var bar = bars[remainingIndex];
    
                sumvolms += bar.Volume;
    
                if (cma3 < bar.HighPrice && cma3 > bar.LowPrice)
                {
                    double newvol = sumvolms / sumvols;
    
                    //NOTE: This is where we started where you're trying to use an aggregate on a single value
                    //having taken a closer look at the code I wonder if you should be adding the newvol to
                    //an existing list of volumes (1 for each time we loop here) and then get the aggregate
                    //of the result so you end up producing 1 CWW value each time through the outer loop?
                    // Move newvols outside for loop, above it
                    //var newvols = new List<double>();
                            
                    //Add current newvol to list
                    //newvols.Add(sumvolms / sumvols);
    
                    //Move aggregate calculation outside for loop, below it to produce a single CWW for the outer loop
                    //double CWW = newvols.Aggregate(( x, y ) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);   
    
                    //The net result would be 1 CWW for each bar from fromIndex to index, you would need to store
                    //that value in a list as well and that list would be defined outside the outer for loop (at the top of the method)
                    //and then add the CWW to it here
                }
            }
            //}
        }
    }

    Some notes.

    1. There was code in there that wasn't actually doing anything that had any effect so I commented it out.

    2. The remaining code I broke up into functions so it became more clear what they are doing.

    3. The original issue of the Aggregate is still present but with the simplified code it might make more sense what is going on.

    4. I added a BarData type to collect the initial set of data for the bars so there wasn't method calls all over the place. This data can be expanded to capture any data you need for a bar that does not vary over the method call.

    5. I prefer IEnumerable<T>, foreach and LINQ but it has a performance overhead compared to List<T> and for so I stuck with your for loop. It makes the code easier to read and probably run better.

    6. I still feel there is redundant calculations going on there but without comparing running values it is hard to say.


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, August 27, 2020 10:03 PM
  • Good morning Cool,

    You are right by moving aggregate calculation outside of brackets it return the closest for each cma's.

    Problem solve! Thank you for all your help. I am closer from finishing this project.

    Thank you also to Karen.

    • Marked as answer by Frankdot Friday, August 28, 2020 12:46 PM
    Friday, August 28, 2020 12:46 PM
  • I have to ask, what if i have multiple formulas.

    Do i have to create:

    var newvols = new List<double>();

    var newvols1 = new List<double>();

    var newvol2 = new List<double>();

    and for aggregate is it possible to do something like:

    double CWW = newvols1.newvols.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);

    Ty

    Friday, August 28, 2020 1:30 PM
  • If you need to collect multiple pieces of information then I would recommend a simple data structure to store them. That is sort of what I did for the BarData. Rather than enumerating the items multiple times just to get a single value you can enumerate once and store any calculated values in a single aggregate data structure. Of course the assumption is each value needs to enumerate in a similar manner.

    public class MyAggregateData
    {
       public double Value1 { get;set;}
       public double Value2 { get; set; }
    }
    
    for (...)
    {
       var barAggregateData = new MyAggregateData();
      
       //Set properties on aggregate 
    };

    Some of the existing code you had would actually qualify for this but it can get confusing if you're doing different enumerations for different sets of data so I left it alone. In general create a grouping type for all data that is calculated using the same enumeration process. 

    The Aggregate method works with any IENumerable<T> type including List<T> and arrays. The method itself gets the T that is being enumerated so if `newvols`.newvols` is a List<T> or array then yes aggregate works. But you cannot access data outside the current T instance without getting into more complex code. At that point a foreach/for statement would be better.


    Michael Taylor http://www.michaeltaylorp3.net

    Friday, August 28, 2020 3:05 PM
  • I think by aggregating a new list it works:

    double CWW = newvols.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);

    double CW2 = Nalists.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);

    var newlist = new List<double>() {CWW,CW2};

    double df = newlist.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);

    Print("newlist" + df);

    but its gonna be labourious


    • Edited by Frankdot Friday, August 28, 2020 5:44 PM
    Friday, August 28, 2020 5:43 PM
  • The more there's bars on the chart the slower it gets. At 200 bars its fine at 2000 bars it freeze.

    Too much data or my script is to heavey?

    Friday, August 28, 2020 7:23 PM
  • A little of both. 2000 bars is a lot of data for someone to understand. I'd cut that down. But the perf is going to be in all the enumerating you're doing. It will get progressively worse each time you add a bar. 

    Let's look at the numbers (based upon your earlier code sample you had and noting there might be some off by 1 errors). Suppose you have 2 bars (FromIndex = 0, ToIndex = 2, index = 1).

    Your outer loop executes 2 times (FromIndex to index). The outer loop has 3 child loops (A, B and C).

    The first pass child loop A goes from current to ToIndex (0 to 2 or 3 times). Loop B goes from current to index (0 to 1 or 2 times). Loop C goes from index to ToIndex (1 to 2 or 2 times). That is 7 additional iterations.

    The second pass child loop A runs 2 times (1 to 2), loop B runs 1 time (1 to 1) and loop C runs 2 times (1 to 2) for a total of 5 times.

    So for a 2 bar with the index of 1 you have 12 iterations.

    If we change index to 2 then we have an extra outer loop plus the inner loops go up. As we add more bars then the inner loops take longer and as index goes up we do more looping on the outer loop which increase the inner looping.

    I suspect by even 100 bars the performance is bad. To work around this you have to get your looping down. That is partially why I recommended aggregating your data once with a single pass. That means your cma calculation is going to have to get a lot smarter as it cannot keep requiring an iteration. You might need to do a running sum or something where each time through the loop you reduce cma based upon the current iteration values. I'm not sure on this though.

    The other thing to consider doing is calculating these values as part of adding them to the bar data. That is sort of what the BarData thing was doing. Or at least as much of data as can be calculated in advance. Then use the calculated values in your larger method. The key is you need to move at much of the calculations outside your method such that you don't need to enumerate all the bars every time. 

    Ultimately if you cannot get rid of the many enumerations inside the method then there is very little you'll be able to do to speed it up as the bars get larger.


    Michael Taylor http://www.michaeltaylorp3.net

    Friday, August 28, 2020 9:32 PM
  • This morning i tried to delete everything that is not needed. Its still slow above 3 days chart but at least its not crashing anymore.

    I work on Ninjatrader.com plateform and its limits. They have two main class Onbarupdate and OnRender. I work on OnRender because i have not been able to index in OBU my cma's. In OBU you have series of data in the form of Volume[0], CurrentBar, but if you want the highest price you still need to for loop the barIndex unless there's a way to do it with linq. They say OBU is faster.

    A number representing the current bar in a Bars object that the OnBarUpdate() method in an indicator or strategy is currently processing. For example, if a chart has 100 bars of data, the very first bar of the chart (left most bar) will be number 0 (zero) and each subsequent bar from left to right is incremented by 1.

     https://ninjatrader.com/support/helpGuides/nt8/

    So i use OR but i have 4 loops that get each different sets of data. The first and third loop are the same, the problem is i need item to apply index. I dont see how it is possible to eleminate the first loop and apply the third one on itself? 

    This line probably causing trouble with all the aggregating of aggregates:

    var newlist = new List<double>() {CWW,CW2,CW3,CW4,CW5,CW6,CW7,CW8,CW9,CW10,CW11,CW12,CW13,CW4,CW15,CW16,CW17,CW18,CW19,CW20,CW21,CW22,CW23,CW24,CW25,CW26,CW27,CW28,CW29,CW30,CW31,CW32,CW33,CW34,CW35,CW36};

    double df = newlist.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);

    Now i have to find a way to extract the results from the aggregated list to compare each one by one to the Close Price which will become the new CP and after that the closest number from the CP0 and so on. 

    Meaning if close price is at bar 100 i have to extract the closest price in bar 99 and bar 101 to compare to the CP of 100. The result will become the new CP (for example 101) and find the closest price from 101 between 100 and 102, if its 102, 102 price become the new close and so on.

    Thanks


    • Edited by Frankdot Monday, August 31, 2020 12:50 PM
    Monday, August 31, 2020 12:49 PM
  • Aggregating that little list is not going to slow the overall algorithm down I believe. You can use Stopwatch to time portions of your code or use a Profiler to identify where the slowdown is. I doubt it is this area. However if you want to speed it up ever so slightly then change from a List<double> to simply an array and you'll save a fractional amount of time. If you want to save even more then move the array outside the loops and inside the loops replace your various CWW# variables with the array index instead (e.g. CWW = array[0], CW2 = array[1], etc). This makes the code harder to read but will reduce an array allocation and assignment of all the fields. Everything else will be the same speed.

    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, September 1, 2020 1:18 PM
  • For the array i cant say it make a big difference. You know any free software to make test on the code. You mention stopwatch, any free online? 

    By the way i changed ChartBars.ToIndex and ChartBars.FromIndex for foundIndex +1 and foundIndex - 1 to reduce the amount of data. It reduce the data process to 10 % maybe, so its not data related, more a nested for loop issue.

    Now i am trying to extract my nearclose result from an aggregated list, but no luck, code only return the last value and not the closest from close price.

    var nearlist = new List<double>();
    				
    				
    nearlist.Add(((cma3 - lowPrice0) * df) + lowPrice0);
    			
    double closest = nearlist.Aggregate((x, y) => Math.Abs(x - Close.GetValueAt(CurrentBar)) < Math.Abs(y - Close.GetValueAt(CurrentBar)) ? x : y);
    			
    			
    Print("clo" +closest);
    				

    Of course the code is outside all brackets, so it return one value but not the closest from Close.GetValueAt(CurrentBar). Strange that the same trick wont work twice.

    I have to imagine a way to compare all those data and loop again. Too many loops darn, and i need them.

    Thanks


    Tuesday, September 1, 2020 2:57 PM
  • Stopwatch is a class in .NET. It is the quick and dirty solution. For more thorough diagnostics use Benchmark. This is the library that they use to benchmark framework changes in most blog posts. 

    External tools aren't useful as they need to instrument the code to identify which lines are slowing things down. But if you want a separate tool then use a profiler. Refer to this Stackify article on it. .NET used to have a profiler but I don't know how good it is or even if it is used anymore. 


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, September 1, 2020 3:05 PM
  • Like i said on my last post with the indexing of the cma, i end up with one value per cma.

    If i try to list  them and apply the lambda it only return the last value. Is there a way (method) i can regroup all the values from the cma's and get only one value for all cma's. 

    Cause list, array wont make it. The problem is the indexing it seperates the values of all cma's as long as they are inside the bracket, but outside it only return the last value.

    Thanks

    Monday, September 7, 2020 12:31 PM
  • So you're saying that the following code you posted only returns the last value?

    var nearlist = new List<double>();
    				
    				
    nearlist.Add(((cma3 - lowPrice0) * df) + lowPrice0);
    			
    double closest = nearlist.Aggregate((x, y) => Math.Abs(x - Close.GetValueAt(CurrentBar)) < Math.Abs(y - Close.GetValueAt(CurrentBar)) ? x : y);
    			
    			
    Print("clo" +closest);
    			

    Since the list has a single value it will only ever return that one value. This is where we started at. It is almost always wrong to create a list with a single value in it. There is absolutely no benefit to this. A list with a single value and aggregate is equivalent to just using the single value. So you'll never get what you want.

    If you want to get the closest from all your cmas then you need to apply the aggregate to the list of cmas you want to find the closest of. This will not involve creating a new list.

    //List of all values for which you want to find the closest
    List<double> cmasThatIWantToFindClosestOf...
    
    //Set a breakpoint here and run your code
    //Verify all cmas that you want to test against are in list
    //If they aren't then you have a bug earlier in the code
    //Go back and fix the code until this list contains
    //all the cmas you want to search...
    
    //Now use the aggregate to find the closets
    double closest = cmasThatIWantToFindClosestOf.Aggregate(...

    Note also that you are calling `Close.GetValueAt(CurrentBar) twice inside the aggregate (times the # of items). This will always return the same value so move that call outside the aggregate into a temp variable and then just use the temp variable.

    To clarify you'll run this aggregate only after you have collected all the cmas that you want to search. If that is happening across multiple loops then create this list variable outside the loop that calculates cma and after determining cma add the value to this list. This will save you from creating extra dummy variables.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, September 7, 2020 3:35 PM
  • Sorry my explanation was not clear.

    var newlist = new List<double>() {CWW,CW2,CW3,CW4,CW5,CW6,CW7,CW8,CW9,CW10,CW11,CW12,CW13,CW4,CW15,CW16,CW17,CW18,CW19,CW20,CW21,CW22,CW23,CW24,CW25,CW26,CW27,CW28,CW29,CW30,CW31,CW32,CW33,CW34,CW35,CW36};
    				
    //each CW is the result of a formula that return values.
    
    
    double df = newlist.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    				
    //df variable return the closest value from fibo2 for each cma. 10 cma's = 10 values				
    				
    				
    double nearclose0 = ((cma3 - lowPrice0) * df) + lowPrice0;
    				
    
    //nearclose transform the values into price
    
    
    List<double> nearlist = new List<double>() {nearclose0};
    						
    				
    double closest = nearlist.Aggregate((x, y) => Math.Abs(x
    Close.GetValueAt(CurrentBar)) < Math.Abs(y
    Close.GetValueAt(CurrentBar)) ? x : y);	
    							
    // by doing another list and aggregate i was hoping
    // to get the closest price from the Close, 1 price for
    all the cma's but it keep returning 1 price per cma's
    									
    }

    That's why i ask if there is a way i can collect all values of the cma's to ge the closest. I try with List, Array and i am stuck. The creation of many cma's prevent me from collecting the value of each of the cma. If i try to aggregate outside the brackets it will return the last value of the last cma but not the closest from Close.

    Thanks

    Tuesday, September 8, 2020 12:17 PM
  • I assume here that `newlist` and all the code after that is being called inside one of your loops. I also assume that for all those values in that current iteration you want to get the closed (nearClose0). Then once you've done this for all the values you want to do a final aggregate on all the nearClose0 values to produce the closest value. This would be 2 separate enumerations (it has to be) and you need to promote your list up. Something like this.

    //Assumed original code
    for (...) 
    {
       var newlist = new List<double>();
       ...
    
       var nearClose0 = newlist.Aggregate(...);
    
       var closest = newClose0...;
    }
    
    //Two enumerations so promote the inner list up
    var closestValues = new List<double>();
    
    for (...)
    {
       var newlist = new List<double>();
       ...
    
       var nearClose0 = newlist.Aggregate(...);
    
       //Got the closest for the current iteration so
       //save it into a list so we can use it later
       closestValues.Add(nearClose0);
    };
    
    //Done enumerating now find the closest of all of them
    var closest = closestValues.Aggregate(...);
    Just a guess here though. This would produce a single value from the closest values you calculated inside the loop. Note that if you're using an aggregate type like I recommended instead of raw double values then the closest value could be associated with the data object you're currently enumerating instead and eliminate the need for the outer list. Once you've updated the closest value for each object you would simply aggregate the master list a final time to get the closest. But one step at a time.


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, September 8, 2020 1:56 PM
  • If by for(..) you mean use count to enumerate all in the newlist

    for(int a = 0; a < nearlist.Count; a++)
      {

                Print("a"+a);
      }

    It will return a bunch of zero's. and you can not use a to aggregate :

    a.Aggregate((x, y) => Math.Abs(x - Close.GetValueAt(CurrentBar)) < Math.Abs(y - Close.GetValueAt(CurrentBar)) ? x : y);

    it will return an error. 

    Tuesday, September 8, 2020 2:59 PM
  • No, I mean the for (...) is the same code you're already using to enumerate whatever that ultimately generates the list of items you are using to generate that nearlist array. Perhaps posting the updated code would be useful.

    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, September 8, 2020 3:13 PM
  • I try this and it returns closest by cma and not closest price for all cma's.

    var newlist = new List<double>() {CWW,CW2,CW3,CW4,CW5,CW6,CW7,CW8,CW9,CW10,CW11,CW12,CW13,CW4,CW15,CW16,CW17,CW18,CW19,CW20,CW21,CW22,CW23,CW24,CW25,CW26,CW27,CW28,CW29,CW30,CW31,CW32,CW33,CW34,CW35,CW36};
    				
    double df = newlist.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    				
    				
    var nearclose0 = new List<double>();
    				
    nearclose0.Add(((cma3 - lowPrice0) * df) + lowPrice0);
    				
    double NC = nearclose0.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    				
    	Print("NC"+NC);
    				
    				
    var nearlist = new List<double>() {NC};
    					
    double close = nearlist.Aggregate((x, y) => Math.Abs(x - Close.GetValueAt(CurrentBar)) < Math.Abs(y - Close.GetValueAt(CurrentBar)) ? x : y);
    				
    					
    Print("clo" +close);

    It seems that part of the code that creates the multiple cma's prevent the listing of nearclose independantly from the cma's.

    for(int barIndex0 = ChartBars.FromIndex; barIndex0 <= index; barIndex0++)
    	{
    	totalI = barIndex0;
    					
    					
    					 
    					 
    List<int> sumlist = new List<int>() {totalI};
    				  
    				
    
    foreach(var item in sumlist) //create multiple cma's
    	{
    		Print("ar"+item);


    • Edited by Frankdot Tuesday, September 8, 2020 3:39 PM
    Tuesday, September 8, 2020 3:34 PM
  • I keep saying this and I'm struggling to understand why you keep doing it. Your code will never work the way you want because you keep creating a list with a single item in it. Please stop doing that. In fact never do that. So right now remove every single place in your code where you create a list and add a single item to it. Once you do that you'll have broken code. Now identify what data you already have that is needed to produce the result you need. This will fix your issue.

    var newlist = new List<double>() {CWW,CW2,CW3,CW4,CW5,CW6,CW7,CW8,CW9,CW10,CW11,CW12,CW13,CW4,CW15,CW16,CW17,CW18,CW19,CW20,CW21,CW22,CW23,CW24,CW25,CW26,CW27,CW28,CW29,CW30,CW31,CW32,CW33,CW34,CW35,CW36};
    				
    double df = newlist.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    				
    //Stop doing this, it will never work				
    //var nearclose0 = new List<double>();				
    //nearclose0.Add(((cma3 - lowPrice0) * df) + lowPrice0);
    
    //This is now broken by design
    //What list of items do you want to scan through to get the list? The cmas? If so then use the list of cmas that you have already instead of `nearclose0`. If you aren't capturing the calculated cmas in their own list then do that first and then enumerate the cma list separately.			
    double NC = nearclose0.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    				
    	Print("NC"+NC);
    				
    //Stop doing this, it will never work				
    //var nearlist = new List<double>() {NC};					
    
    //Assuming you want the closest out of all the closest values from the cmas (so each cma has a single closest) then use the list produced in the previous loop above
    double close = nearlist.Aggregate((x, y) => Math.Abs(x - Close.GetValueAt(CurrentBar)) < Math.Abs(y - Close.GetValueAt(CurrentBar)) ? x : y);
    				
    					
    Print("clo" +close);
    I see your algorithm as having a first loop that figures out cma values and stores them in a list. The second loop runs through the cma list produced in the previous loop and calculates the closest value for each cma. This is stored in yet another list. The final call is to aggregate the closest list to produce a single value from all the cma's closest values. But maybe I misunderstand your algorithm.


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, September 8, 2020 4:16 PM
  • Now i think i understand what your saying. Correct me if i am wrong.

    var newlist = new List<double>() {CWW,CW2,CW3.....

    // represent a one element list thats why i cant extract the closest

    Now CWW, CW2, CW3 are doubles:

    double CWW = newvols.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    						
    
    double CW2 = Nalists.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);
    						
    double CW3 = Nblists.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);		
    				

    Each return one element, a value converted into price that return the closest price from Close Price. 

    Using 

    double df = newlist.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);

    double nearclose0 = ((cma3 - lowPrice0) * df) + lowPrice0;

    I need to sracp those two lines to be able to make all my CW one big list that i will compare to my close price.

    I dont see how to do that. The problem will always come back at some point because i will need to create a list. How can i merge all my CW's without ending up with one element in a list? Somewhere i have to extract each value of the CW's and create a new list.

    I could be using concat or union? That would mean one list by CW's and than merge them all in the hope to get all the values in the same list.

    Tuesday, September 8, 2020 5:24 PM
  • `newlist` is not a one element list. An element is the item in the list. So if you have 10 items in the list then you have 10 elements. Your `newlist` variable has a list of what looks like 36 elements (CWW, CWW2, etc). Aggregating on that makes sense.

    So the question is now what? You have this list of items in it. What do you want to do with that list? You can aggregate that list to produce a single result based upon all the values in the list if you need to. So semantically this makes sense:
    double df = newlist.Aggregate((x, y) => Math.Abs(x - fibo2) < Math.Abs(y - fibo2) ? x : y);

    But whether that makes sense for your algorithm I cannot say as I don't understand what it is doing because the code itself. The above code would enumerate each of your CWW variables (in the list) and find the one that is closest to fibo2, I think. Does that make sense for all your CWW values? I have no idea.

    This line:

    double nearclose0 = ((cma3 - lowPrice0) * df) + lowPrice0;

    doesn't work though in my opinion. There is no cma3 in the list of CWW values. If it needs to be calculated based upon the previous aggregate then you are applying (for a single cma3 and lowPrice0 value) the result aggregating all the CWW values. Again I have no idea if this makes sense or not. If it does then the result is a single value so no list is needed. 

    So do you expect a single `nearclose0` value for each element in newlist (in other words for each CWW value)? If so then inside this formula where does the CWW value fit in because `df` is already a single value across the entire list.


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, September 8, 2020 6:12 PM
  • Imagine each CW return 10 values per CMA's and they are 10 cma's, that makes 100 returns. 

    newlist create a list of 100  values and df return one value per cma's that gives us 10 returns because we have 10 cma's.

    Now nearclose0 is not a problem because cma3, lowprice are variables from the beginning of the code and it convert all 10 returns in price. Lets say : 8$, 10$, 12$ etc 

    The actual trading price is 13$ "Close.GetValueAt(CurrentBar)" so the closest is 12$. 

    But i cant get the 12 $ because the  aggregating of nearclose0 will return again cma1 = 8$, cma2 = 10$ etc.

    It wont regroup in the list all price to be compare. 

    List<double> nearlist = new List<double>() {nearclose0};

    double closest = nearlist.Aggregate((x, y) => Math.Abs(x - Close.GetValueAt(CurrentBar)) < Math.Abs(y - Close.GetValueAt(CurrentBar)) ? x : y);
    Print("items"+closest);

    ar is the number of the cma

    closest is the closest price for that cma.


    ar50
    3cma3360,56031031785
    closest3351,58685227703
    ar51
    3cma3360,53542789837
    closest3351,55274008888
    ar52
    3cma3360,42971466321
    closest3351,54985327506
    ar53
    3cma3360,50948028871
    closest3351,52346698834
    ar54
    3cma3360,50963549111
    closest3351,50477153748

    What i want is the closest for ar50 to ar54. Only one price for all 5 cma.

    I tried with 

    List<double> values = new List<double>();
      values.Add(CWW);
      values.Add(CW2);
      values.Add(CW3);

    but no luck its like i said earlier the indexing of cma seems to force division on everything inside the scope of the brackets and if i remove one part of the code it will mess the algo.

    for(int barIndex0 = ChartBars.FromIndex; barIndex0 <= index; barIndex0++)
    	{
    	totalI = barIndex0;
    					
    					
    					 
    					 
    List<int> sumlist = new List<int>() {totalI};
    				  
    				
    
    foreach(var item in sumlist) //create multiple cma's
    	{
    		Print("ar"+item);

    Tuesday, September 8, 2020 6:40 PM
  • Ok, you keep mixing up terms and it is really confusing. You are using CWW and cma almost interchangeable. Please use the variable names only when talking about your code.

    Based upon your 10 values of 10 it sounds like you have flattened an array of 10 values so it seems CWW-CWW10 are 10 related values, CWW11-CWW20 are the next set of 10 values, etc. Is that correct? If so then you shouldn't flatten them if you need them separated. Just create a list of arrays. Then you can aggregate each group of 10 values.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, September 14, 2020 2:14 PM