使用二维数组计算 win/lose

Working on two-dimensional arrays to calculate win/lose

我在两个对象数组中跟踪我的交易组合。

特定交易货币的卖出和买入如下:

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


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

我正在尝试以下操作:

LIFO的方式计算我的输赢百分比。这意味着我想采用最近的卖出并开始从最近的买入中减去 price/amount,然后向后移动。

如果我的卖出量足够大,这意味着我不仅需要查看之前的买入量,还需要搜索未知数量的先前买入量,直到我的卖出量用完,这样我才能可以算出我的win/lose.

我的难处在于,由于卖出和买入是在不同的amount/prices上进行的,所以我很难计算出结果。

这意味着例如:

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,

这意味着在每次卖出时我都需要向后看并递归地查看我购买它的价格并根据金额 sold/bought.

计算 win/lose

我不是在寻找解决方案,只是在寻找一些指南或建议。

如果我们想到 LIFO 交易,我们可以将其转化为称为堆栈的数据结构中元素的概念,其中具有操作 push/pop:

每笔交易有五个变量:买入金额、买入类型、卖出金额、卖出类型和日期。

function Trade(buyAmount, buyType, sellAmount, sellType, date) {

    this.buyAmount = buyAmount;
    this.buyType = buyType;
    this.sellAmount = sellType;
    this.date = date;

}

这是一个JavaScript对象的构造函数,可以这样调用:

var trade = new Trade("Bitcoin", 1.0, "Ethereum", 10.0, new Date("5/30/2018"));

函数调用前的关键字 new 创建一个对象,并且在该函数中使用的 this 成为对该新对象的引用。然后将该对象分配给变量trade。 (研究this很厉害。)

无论如何,接下来您需要创建一个按日期排序的数组,并创建一个算法,使每笔交易的毛利交易与所售商品的类型相关,即类似于以下内容的字典:

var profit = { Bitcoin: 0, Ethereum: 0 }

这是一个很好的起点,我使用这种相同类型的数据结构来计算 2017 年我的加密货币收益的税收。

您可以获取交易并维护总单位数和总价两个指标。售价与实际购买商品的计算无关

请看FIFO and LIFO accounting

要获得一些已售商品的实际价值,将检查最后一次购买,如果最后一次购买的单位数量小于或等于已售出的单位,则更新总价值以及实际单位,直到所有单位均取自最新购买。

如果某些购买有剩余的单位,则将此信息添加到项目数组中。

因此,维护了一个包含最后购买和销售的动态数组。

                                                  ------------------
                                                       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; }