Search code examples
javascriptalgorithmtrading

Working on two-dimensional arrays to calculate win/lose


I am tracking my trading portfolio in two arrays of objects.

The sells and the buys for a specific trade currency as follows:

var sell {
    sold_amount: sold,
    bought_amount: bought,
    price : price
}


var buy {
    sold_amount: sold,
    bought_amount: bought,
    price : price
}

I am trying to the following:

Calculate my win-lose percentage in a LIFO manner. That means that I want to take the latest sell I made and start subtracting the price/amount from the latest buy and then move backwards.

If my sell was big enough, it would mean that I would need to look not only on the previous buy, but I would need to search an unknown number of previous buys until all my sell amount is exhausted so that I can calculate my win/lose.

My difficulty is that since sells and buys are done on different amount/prices, it is really difficult for me to calculate the result.

That means for example:

I bought 20 units of  $javascript paying 32 units of $c++ ,
I bought 17 units of  $javascript paying 29 units of $c++ ,
I sold   57 units of  $c++        paying 31 units of $javascript,
I bought 22 units of $javascript  paying 22 units of c++,
I sold   12 units of  c++         paing  11 units of $javascript,

That means that at every sell I would need to look backwards and see the price I bought it recursively and calculate the win/lose according to the amount sold/bought.

I am not looking for a solution, just some guidelines or some advice.


Solution

  • You could take the transactions and maintain two indicators for total units and total price. The selling price does not matter for the calculation of the actually bought products.

    Please have a look to FIFO and LIFO accounting.

    To get an actual value with some sold items, the last buy is checked and if the last amount of units is smaller or equal to the sold units, the total values are updated, as well as the actual unit, until all units are taken from the latest buy.

    If some buy has a rest of units, then this information is added to the items array.

    As result, a dynamic array is maintained with the last purchases buys and sales.

                                                      ------------------
                                                           t o t a l
     action     units     price     calc      price     units     price   comment
    --------  --------  --------  --------  --------  --------  --------  -----------------
      buy         20        32     20 * 32      640       20       640
      buy         17        29     17 * 29      493       37      1133
      sell        22        22    -17 * 29     -493       20       640    take last first
                                  - 5 * 32     -160       15       480    take next to last
      buy         31        57     31 * 57     1767       46      2247
      sell        11        12    -11 * 57     -627       35      1620
                                                      ------------------
    

    var transactions = [
            { action: 'buy', product: 'foo', units: 20, price: 32 },
            { action: 'buy', product: 'foo', units: 17, price: 29 },
            { action: 'sell', product: 'foo', units: 22, price: 22 },
            { action: 'buy', product: 'foo', units: 31, price: 57 },
            { action: 'sell', product: 'foo', units: 11, price: 12 }
        ],
        accounts = {};
    
    transactions.forEach(({ action, product, units, price }) => {
        var last;
        accounts[product] = accounts[product] || { items: [], totalUnits: 0, totalPrice: 0 };
    
        if (action === 'buy') {
            accounts[product].totalUnits += units;
            accounts[product].totalPrice += units * price;
            accounts[product].items.push({ units, price });
        } else {
            while (units) {
                last = accounts[product].items.pop();
                if (last.units <= units) {
                    accounts[product].totalUnits -= last.units;
                    accounts[product].totalPrice -= last.units * last.price;
                    units -= last.units;
                    continue;
                }
                accounts[product].totalUnits -= units;
                accounts[product].totalPrice -= units * last.price;
                last.units -= units;
                units = 0;
                accounts[product].items.push(last);
            }
        }
        console.log(accounts);
    });
    .as-console-wrapper { max-height: 100% !important; top: 0; }