algorithm to process a list of transactions [typescript]

I am kind of stuck on how to achieve my desired output.

I just want a bit of help on how should I approach this problem, as I am a junior dev trying to build out a project and I feel that I am overcomplicating things here and still not getting what I want.

The problem:
I have a large array of object, here is a chunk of them:

const trades: Trade[] = [
  { side: 'BUY', asset: 'ETH', quantity: 50, price: 1800 },
  { side: 'BUY', asset: 'ETH', quantity: 20, price: 1850 },
  { side: 'SELL', asset: 'BTC', quantity: 25, price: 36800 },
  { side: 'SELL', asset: 'ETH', quantity: 5, price: 1900 },
  { side: 'BUY', asset: 'BTC', quantity: 10, price: 37000 },
  { side: 'SELL', asset: 'ETH', quantity: 40, price: 1700 },
  { side: 'SELL', asset: 'ETH', quantity: 25, price: 1750 },
  { side: 'BUY', asset: 'BTC', quantity: 15, price: 35000 },
  { side: 'BUY', asset: 'BTC', quantity: 5, price: 39000 },
  { side: 'SELL', asset: 'BTC', quantity: 5, price: 38500 },
  { side: 'SELL', asset: 'ETH', quantity: 80, price: 1350 },
];

interfaces:

interface OriginTrade {
  side: 'BUY' | 'SELL';
  asset: string;
  quantity: number;
  remainingQuantity: number;
  linkedTrades: MatchedTrade[];
}

interface MatchedTrade {
  trade: Trade;
  remainingQuantity: number;
  index: number;
}

interface Trade {
  side: 'BUY' | 'SELL';
  asset: string;
  quantity: number;
  price: number;
}

The code itself:

const originTrades: OriginTrade[] = trades.reduce<OriginTrade[]>(
  (acc, curr, i) => {
    const { side, asset, quantity } = curr;

    if (!acc[asset]) {

      const originQuantity = side === 'SELL' ? -quantity : quantity; // transform quantity into negative if side is SELL
      acc[asset] = curr;  // If there is no existing origin trade for this asset, set the current trade as the origin trade

      // and push the trades into the array
      acc.push({
        side: side,
        asset: asset,
        quantity: originQuantity,
        linkedTrades: [],
        remainingQuantity: originQuantity,
      });

    } else {

      // if there is an existing previous trade get it and also the side
      // const existingTrade = acc[asset];
      const existingTrade = acc.find((trade) => trade.asset === asset)!;


      // set the math operator based on the side 
      const operator = curr.side === 'BUY' ? '+' : '-';

      // then use that operator to calculate  remaining quantity
      const calculateRemainingQuantity = eval(existingTrade.remainingQuantity + operator + quantity);

      // set the quantity of the current trade based on the side
      curr.quantity = curr.side === 'SELL' ? -curr.quantity : curr.quantity;

      // const existingTradeSide = existingTrade.side;
      existingTrade.linkedTrades.push({ trade: curr, remainingQuantity: calculateRemainingQuantity, index: existingTrade.linkedTrades.length });

      existingTrade.remainingQuantity = calculateRemainingQuantity;

    }

    return acc;
  },
  []
);

console.log('actuall output', originTrades);

What I want to achieve is the following:

  1. if there is no ‘originTrade’, then assign the first of its kind a an origin trade
  2. in the originTrade for the given asset, add all the upcoming trades into the linkedTrades[], IF the quantity (or balance) is above 0 (therefore we know that the position is not fully closed yet)
  3. when goes to 0 or is below 0, then create another ‘originTrade’ object and assign all the upcoming trades into the linkedTrades[].

What part I am struggling with:

  • I have achieved assigning the trades into the initial originTrade and linked all the individual trades into the linkedTrades for that given asset using the reduce, but I am running short on ideas how to achieve that when the remainingQuantity for that given originTrade hits 0 or below 0, then create another originTrade and start linking the trades into that new one.

I feel that I am overcomplicating the code at this point.
Any help would be really appreciated!

Here is the expected output I want to achieve:

 [
  {
    "side": "BUY",
    "asset": "ETH",
    "quantity": 50,
    "linkedTrades": [
      {
        "trade": {
          "side": "BUY",
          "asset": "ETH",
          "quantity": 20,
          "price": 1850
        },
        "remainingQuantity": 70,
        "index": 0
      },
      {
        "trade": {
          "side": "SELL",
          "asset": "ETH",
          "quantity": -5,
          "price": 1900
        },
        "remainingQuantity": 65,
        "index": 1
      },
      {
        "trade": {
          "side": "SELL",
          "asset": "ETH",
          "quantity": -40,
          "price": 1700
        },
        "remainingQuantity": 25,
        "index": 2
      },
      {
        "trade": {
          "side": "SELL",
          "asset": "ETH",
          "quantity": -25,
          "price": 1750
        },
        "remainingQuantity": 0,
        "index": 3
      }
    ],
    "remainingQuantity": 0
  },
  {
    "side": "SELL",
    "asset": "BTC",
    "quantity": -25,
    "linkedTrades": [
      {
        "trade": {
          "side": "BUY",
          "asset": "BTC",
          "quantity": 10,
          "price": 37000
        },
        "remainingQuantity": -15,
        "index": 0
      },
      {
        "trade": {
          "side": "BUY",
          "asset": "BTC",
          "quantity": 15,
          "price": 35000
        },
        "remainingQuantity": 0,
        "index": 1
      }
    ],
    "remainingQuantity": 0
  },
  {
    "side": "SELL",
    "asset": "ETH",
    "quantity": -80,
    "linkedTrades": [],
    "remainingQuantity": -80
  },
  {
    "side": "BUY",
    "asset": "BTC",
    "quantity": 5,
    "linkedTrades": [
      {
        "trade": {
          "side": "SELL",
          "asset": "BTC",
          "quantity": -5,
          "price": 38500
        },
        "remainingQuantity": 0,
        "index": 3
      }
    ],
    "remainingQuantity": 0
  }
]

And here is the output I am getting now:

[
    {
        "side": "BUY",
        "asset": "ETH",
        "quantity": 50,
        "linkedTrades": [
            {
                "trade": {
                    "side": "BUY",
                    "asset": "ETH",
                    "quantity": 20,
                    "price": 1850
                },
                "remainingQuantity": 70,
                "index": 0
            },
            {
                "trade": {
                    "side": "SELL",
                    "asset": "ETH",
                    "quantity": -5,
                    "price": 1900
                },
                "remainingQuantity": 65,
                "index": 1
            },
            {
                "trade": {
                    "side": "SELL",
                    "asset": "ETH",
                    "quantity": -40,
                    "price": 1700
                },
                "remainingQuantity": 25,
                "index": 2
            },
            {
                "trade": {
                    "side": "SELL",
                    "asset": "ETH",
                    "quantity": -25,
                    "price": 1750
                },
                "remainingQuantity": 0,
                "index": 3
            },
            {
                "trade": {
                    "side": "SELL",
                    "asset": "ETH",
                    "quantity": -80,
                    "price": 1350
                },
                "remainingQuantity": -80,
                "index": 4
            }
        ],
        "remainingQuantity": -80
    },
    {
        "side": "SELL",
        "asset": "BTC",
        "quantity": -25,
        "linkedTrades": [
            {
                "trade": {
                    "side": "BUY",
                    "asset": "BTC",
                    "quantity": 10,
                    "price": 37000
                },
                "remainingQuantity": -15,
                "index": 0
            },
            {
                "trade": {
                    "side": "BUY",
                    "asset": "BTC",
                    "quantity": 15,
                    "price": 35000
                },
                "remainingQuantity": 0,
                "index": 1
            },
            {
                "trade": {
                    "side": "BUY",
                    "asset": "BTC",
                    "quantity": 5,
                    "price": 39000
                },
                "remainingQuantity": 5,
                "index": 2
            },
            {
                "trade": {
                    "side": "SELL",
                    "asset": "BTC",
                    "quantity": -5,
                    "price": 38500
                },
                "remainingQuantity": 0,
                "index": 3
            }
        ],
        "remainingQuantity": 0
    }
]

The whole code

HERE IN TS: # https://playcode.io/1450531
Here using JS editor in SO:

const trades = [
  { side: 'BUY', asset: 'ETH', quantity: 50, price: 1800 }, // ORIGIN TRADE n1
  { side: 'BUY', asset: 'ETH', quantity: 20, price: 1850 }, // LINKED TO ORIGIN TRADE n1
  { side: 'SELL', asset: 'BTC', quantity: 25, price: 36800 }, // ORIGIN TRADE n2
  { side: 'SELL', asset: 'ETH', quantity: 5, price: 1900 }, // LINKED TO ORIGIN TRADE n1
  { side: 'BUY', asset: 'BTC', quantity: 10, price: 37000 }, // LINKED TO ORIGIN TRADE n2
  { side: 'SELL', asset: 'ETH', quantity: 40, price: 1700 }, // LINKED TO ORIGIN TRADE n1
  { side: 'SELL', asset: 'ETH', quantity: 25, price: 1750 }, // LINKED TO ORIGIN TRADE n1
  { side: 'BUY', asset: 'BTC', quantity: 15, price: 35000 }, // LINKED TO ORIGIN TRADE n2
  { side: 'BUY', asset: 'BTC', quantity: 5, price: 39000 }, // ORIGIN TRADE n3 
  { side: 'SELL', asset: 'BTC', quantity: 5, price: 38500 },// LINKED TO ORIGIN TRADE n3
  { side: 'SELL', asset: 'ETH', quantity: 80, price: 1350 }, // ORIGIN TRADE n4
];

const originTrades = trades.reduce(
  (acc, curr, i) => {
    const { side, asset, quantity } = curr;

    if (!acc[asset]) {

      const originQuantity = side === 'SELL' ? -quantity : quantity; // transform quantity into negative if side is SELL
      acc[asset] = curr;  // If there is no existing origin trade for this asset, set the current trade as the origin trade

      // and push the trades into the array
      acc.push({
        side: side,
        asset: asset,
        quantity: originQuantity,
        linkedTrades: [],
        remainingQuantity: originQuantity,
      });

    } else {

      // if there is an existing previous trade get it and also the side
      // const existingTrade = acc[asset];
      const existingTrade = acc.find((trade) => trade.asset === asset);


      // set the math operator based on the side 
      const operator = curr.side === 'BUY' ? '+' : '-';

      // then use that operator to calculate  remaining quantity
      const calculateRemainingQuantity = eval(existingTrade.remainingQuantity + operator + quantity);

      // set the quantity of the current trade based on the side
      curr.quantity = curr.side === 'SELL' ? -curr.quantity : curr.quantity;

      // const existingTradeSide = existingTrade.side;
      existingTrade.linkedTrades.push({ trade: curr, remainingQuantity: calculateRemainingQuantity, index: existingTrade.linkedTrades.length });

      existingTrade.remainingQuantity = calculateRemainingQuantity;

    }

    return acc;
  },
  []
);

console.log('actuall output', originTrades);


const expectedOutput = [
  {
    "side": "BUY",
    "asset": "ETH",
    "quantity": 50,
    "linkedTrades": [
      {
        "trade": {
          "side": "BUY",
          "asset": "ETH",
          "quantity": 20,
          "price": 1850
        },
        "remainingQuantity": 70,
        "index": 0
      },
      {
        "trade": {
          "side": "SELL",
          "asset": "ETH",
          "quantity": -5,
          "price": 1900
        },
        "remainingQuantity": 65,
        "index": 1
      },
      {
        "trade": {
          "side": "SELL",
          "asset": "ETH",
          "quantity": -40,
          "price": 1700
        },
        "remainingQuantity": 25,
        "index": 2
      },
      {
        "trade": {
          "side": "SELL",
          "asset": "ETH",
          "quantity": -25,
          "price": 1750
        },
        "remainingQuantity": 0,
        "index": 3
      }
    ],
    "remainingQuantity": 0
  },
  {
    "side": "SELL",
    "asset": "BTC",
    "quantity": -25,
    "linkedTrades": [
      {
        "trade": {
          "side": "BUY",
          "asset": "BTC",
          "quantity": 10,
          "price": 37000
        },
        "remainingQuantity": -15,
        "index": 0
      },
      {
        "trade": {
          "side": "BUY",
          "asset": "BTC",
          "quantity": 15,
          "price": 35000
        },
        "remainingQuantity": 0,
        "index": 1
      }
    ],
    "remainingQuantity": 0
  },
  {
    "side": "SELL",
    "asset": "ETH",
    "quantity": -80,
    "linkedTrades": [],
    "remainingQuantity": -80
  },
  {
    "side": "BUY",
    "asset": "BTC",
    "quantity": 5,
    "linkedTrades": [
      {
        "trade": {
          "side": "SELL",
          "asset": "BTC",
          "quantity": -5,
          "price": 38500
        },
        "remainingQuantity": 0,
        "index": 3
      }
    ],
    "remainingQuantity": 0
  }
]

console.log('expected output', expectedOutput);

I also added an ‘expectedOutput’ JSON there at the end and console logged it.

Thank you!