0

I've been trying to build a recursive function to replace the following n deep nested loop algorithm, the depth will change based on the length of the combination anywhere for 2 to n (most likely less than 20)

    Edit: removed confusing code

I have searched this site and found Converting nested loop and More nested loop conversions but I can't seam to tweak them to output what I need.

or I could just be looking at it wrong and not needing a recursive function at all.

trying to do this in C#, thanks for any help.

Edit: hope this explains things a bit more.

What I’m trying to do is find the best combination of options and amounts to give me maximum return without going over budget.

So I have a cut down list of options that meets my requirements, then I want to feed them into this program/script to get the best combination with highset return, I also need to reduce my risk by buying more than one option normally 3-10

So below is my full code so far fixed at a depth of 3:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace Combinations
    {
        class Program
        {
            static void Main(string[] args)
            {

                Stopwatch stopwatch = new Stopwatch();

                List<option> options = new List<option> {
                            new option("A", 6.50, 0.18, 25000, 3),
                            new option("B", 23.00, 0.59, 25000, 3),
                            new option("C", 27.50, 0.60, 25000, 3),
                            new option("D", 21.00, 0.40, 25000, 3),
                            new option("E", 16.00, 0.30, 25000, 3),
                            new option("F", 7.00, 0.13, 25000, 3),
                            new option("G", 22.50, 0.38, 25000, 3),
                            new option("H", 27.00, 0.45, 25000, 3),
                            new option("I", 13.00, 0.20, 25000, 3),
                            new option("J", 20.50, 0.30, 25000, 3),
                            new option("K", 17.50, 0.25, 25000, 3),
                            new option("L", 10.50, 0.15, 25000, 3),
                            new option("M", 29.00, 0.41, 25000, 3),
                            new option("N", 26.50, 0.37, 25000, 3),
                            new option("P", 15.50, 0.21, 25000, 3),
                            new option("Q", 16.00, 0.20, 25000, 3),
                            new option("R", 10.00, 0.12, 25000, 3),
                            new option("S", 25.00, 0.30, 25000, 3),
                            new option("T", 27.00, 0.32, 25000, 3),
                            new option("U", 22.00, 0.25, 25000, 3),
                            new option("V", 26.50, 0.30, 25000, 3),
                            new option("W", 27.00, 0.30, 25000, 3),
                            new option("X", 14.50, 0.16, 25000, 3),
                            new option("Y", 28.50, 0.31, 25000, 3),
                            new option("Z", 28.50, 0.30, 25000, 3)
                        };
                stopwatch.Start();
                IEnumerable<List<option>> combinations = GetCombination(options, 3);
                stopwatch.Stop();
                Console.WriteLine("Combinations - Time elapsed: {0}", stopwatch.Elapsed);

                stopwatch.Start();
                bestFit(combinations);
                stopwatch.Stop();
                Console.WriteLine("Best Fit - Time elapsed: {0}", stopwatch.Elapsed);

                Console.ReadKey();
            }

            static IEnumerable<List<option>> GetCombination(List<option> list, int _size)
            {
                double count = Math.Pow(2, list.Count);
                List<option> combination = new List<option>();

                int size = 0;

                for (int i = 1; i <= count - 1; i++)
                {
                    for (int j = 0; j < list.Count; j++)
                    {
                        if (((i >> j) & 1) == 1)
                        {
                            combination.Add(list[j]);
                            size++;
                        }
                    }

                    if (size == _size)
                    {
                        yield return combination;
                    }
                    combination.Clear();
                    size = 0;
                }
            }

            static void bestFit(IEnumerable<List<option>> combinations)
            {
                double max = 0d;
                double results = 0d;
                double total = 0d;
                string output = "";
                string tmpOutput = "";

                int y0 = 0;
                int y1 = 1;
                int yn = 2;

                foreach (var combination in combinations)
                {
                    option A1 = combination[y0];
                    for (int x1 = A1.lower; x1 < A1.upper; x1++)
                    {
                        option A2 = combination[y1];
                        for (int x2 = A2.lower; x2 < A2.upper; x2++)
                        {
                            option An = combination[yn];
                            for (int xn = An.lower; xn < An.upper; xn++)
                            {
                                int[] counts = { x1, x2, xn };
                                int i = 0;
                                foreach (option objOption in combination)
                                {
                                    results += objOption.bid * 100 * counts[i] / objOption.cash;
                                    total += (objOption.strike - objOption.bid) * 100 * counts[i];
                                    tmpOutput += objOption.symbol + " STO " + counts[i].ToString() + " @ $" + objOption.strike + ", ";

                                    i++;
                                }

                                if (results > max && total < A1.cash)
                                {
                                    output = tmpOutput.Remove(tmpOutput.Length - 2) + " for a gain of " + results*100 + "% using a total of $" + total;
                                    max = results;
                                }
                                results = 0d;
                                total = 0d;
                                tmpOutput = "";
                            }
                        }
                    }

                }
                Console.WriteLine(output);
            }
        }

        class option
        {
            public string symbol { get; set; }
            public double strike { get; set; }
            public double bid { get; set; }
            public double cash { get; set; }
            public int lower;
            public int upper;

            public option(string _symbol, double _strike, double _bid, double _cash, int _trades)
            {
                this.symbol = _symbol;
                this.strike = _strike;
                this.bid = _bid;
                this.cash = _cash;

                double tradeCash = _cash / _trades;

                this.lower = (int)((0.25 * tradeCash) / ((_strike - _bid) * 100));
                this.upper = (int)((1.25 * tradeCash) / ((_strike - _bid) * 100));

            }
        }
    }

This should give an output of:

Combinations - Time elapsed: 00:00:00.0002575
A STO 15 @ $6.5, B STO 3 @ $23, D STO 4 @ $21 for a gain of 2.428% using a total of $24443
Best Fit - Time elapsed: 00:00:11.9196411

hope this help to clear things up.

Community
  • 1
  • 1
Yendor
  • 135
  • 1
  • 6

1 Answers1

0

it seems as if you are only using the for loops to produce your count entry. I would first begin by refactoring this part out into something like this:

public struct Bound
{
    public int Lower { get; set; }
    public int Upper { get; set; }
}

public static class Counting
{
    public static IEnumerable<int[]> Indizes(this Bound[] bounds)
    {
        return Indizes(bounds, 0);
    }

    static IEnumerable<int[]> Indizes(this Bound[] bounds, int index)
    {
        if (index >= bounds.Length)
            yield return new int[] {};
        else
        {
            foreach(var comb in Indizes(bounds, index+1))
            {
                for (var i = bounds[index].Lower; i < bounds[index].Upper; i++)
                {
                    var newArr = new int[comb.Length + 1];
                    Array.Copy(comb, 0, newArr, 1, comb.Length);
                    newArr[0] = i;
                    yield return newArr;
                }
            }
        }
    }
}

remark mostlikely you can get this faster but I think it shows you how you can do such thinks using recursion

With something like this (replace the Bound struct with your data-structure - it's only in there so I could test my code) your insane-loop simplifies to:

   foreach(var combination in combinations)
   {
        foreach (var counts in Counting.Indizes(combination))
        {
            int i = 0;
            foreach (myClass objMyClass in combination)
            {
               results += objMyClass.a * 100 * counts[i] / objMyClass.b;
               total += (objMyClass.c - objMyClass.a) * 100 * counts[i];
               tmpOutput += objMyClass.symbol + " count " + counts[i].ToString() + ", ";
               i++;
            }
            // ...
        }
   }

for the rest I don't understand your code enough to give any advice

Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • Thanks I'll give your code ago and see if I can fit it to my needs. I've updated my post with my full working development code giving me an output. If you would like to have a look to get a understand. – Yendor Aug 27 '14 at 23:05