4

I have an array that contains a couple of hundred trades objects like so:

Input:

[{
    "trades": {
        "model": "Trades_Information"
        "fields": {
                "orderCloseTime": "2019-03-19T16:20:56",
                "orderOpenPrice": "1.40000",
                "orderClosePrice": "1.44000",
                "orderProfit": "75",
                "orderLots": "1.4"
        },
        [...]
}]

Now I would like to loop all objects and map the results (some calculations included in the loop) to new arrays which will update an Apexchart.

For me the trickie part right now is to get the correct mapping dynamically to the last 12 months since each new array must contain the values in the correct order according to the last 12 months array which I create as follows:

var date = new Date();
var lastMonths = [],
    monthNames = ['Dec', 'Nov', 'Oct', 'Sep', 'Aug', 'Jul', 'Jun', 'May', 'Apr', 'Mar', 'Feb', 'Jan'];
for (var i = 0; i < 12; i++) {
    lastMonths.push(monthNames[date.getMonth()]);
    date.setMonth(date.getMonth() - 1);
}

console.log(lastMonths);

// ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]

So I somehow end up with this brief structure:

// Arrays needed for Apexchart
NetPipsMonth = [];
NetProfitMonth = [];
TotalVolumeMonth = [];
TotalTradesMonth = [];
lastMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

// Loop all trades in trades-object
for (var i = 0; i < tradesTotal; i++) {

    // Filter all trades by closed ones
    closeTime = trades[i].fields.orderCloseTime;
    if (closeTime != null) {

    // Make some calculations that output one value per new array per trade object


    // Push the results to each array in right order according to lastMonths array
    // Mapping with `orderCloseTime`

    }
}

I don't know how to realize the mapping by orderCloseTime in order to have the results in the right place within the needed arrays.

My ideas/thoughts in human language:

  • Define the month of the orderCloseTime for each trade and tell JS which spot in the new arrays is March (example above) using the order of lastMonths and increase it by the result of this particular trade's values to end up with the monthly sum after looping all trade objects.
      lastMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
  NetProfitMonth = [     ,      ,  75  ,      ,      ,];
TotalVolumeMonth = [     ,      ,  1.4 ,      ,  ... ,];
  • Maybe create a nested object and populate this while looping to have all values in one main object and build the needed arrays for apexchart out of this main object after looping is finished
  • Build 12x4 loops for every month containing each calculation and sum the results afterwards to get monthly sums included in 4 arrays (that would end up in a huge amount of code)

Looking forward to your ideas and enjoy the holidays!

Jonas
  • 1,633
  • 1
  • 6
  • 28

2 Answers2

1

You can indeed create the arrays as you suggest. True, it would be more object oriented to group the three values (month, profit, volume) in one object, but as the apexChart expects individual values in arrays, it makes sense to go directly for that structure.

You can use some splice magic to create the months-array.

let tradesTotal = [{
    "trades": {
        "model": "Trades_Information",
        "fields": {
                "orderCloseTime": "2019-03-19T16:20:56",
                "orderProfit": "75",
                "orderLots": "1.4"
        },
    }
}];

let now = new Date();
now.setDate(32); // go to next month
now.setDate(1); // set to first of next month
now.setUTCHours(0, 0, 0, 0); // clear time
let firstMonth = now.getMonth();
let lastMonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
lastMonths.splice(0, 0, ...lastMonths.splice(firstMonth)); // rotate
let netProfitMonth = Array(12).fill(0);
let totalVolumeMonth = Array(12).fill(0);

let clone = new Date(now);
clone.setFullYear(now.getFullYear()-1);
let minDateString = clone.toJSON().slice(0, 10);
for (let {trades: { fields: { orderCloseTime, orderProfit, orderLots }}} of  tradesTotal) {
    if (orderCloseTime < minDateString) continue; // not in last 12 months: skip
    let month = (orderCloseTime.slice(5, 7) - firstMonth + 11) % 12;
    netProfitMonth[month] += +orderProfit;
    totalVolumeMonth[month] += +orderLots;
}

console.log(...lastMonths);
console.log(...netProfitMonth);
console.log(...totalVolumeMonth);
trincot
  • 211,288
  • 25
  • 175
  • 211
1

I would approach this differently. I keep my months array as in normal order. (Jan first Dec last). That would make the calculations of the other arrays easier. Get the month from date use it as index to fill the arrays. Then calculate the rotation amount from the current month and then rotate your arrays.

var tradesArr = [{
  "trades": {
    "model": "Trades_Information",
    "fields": {
      "orderCloseTime": "2019-03-19T16:20:56",
      "orderOpenPrice": "1.40000",
      "orderProfit": "75",
      "orderLots": "1.4"
    }
  }
}, {
  "trades": {
    "model": "Trades_Information",
    "fields": {
      "orderCloseTime": "2019-04-19T16:20:56",
      "orderOpenPrice": "1.40000",
      "orderProfit": "75",
      "orderLots": "1.4"
    }
  }
}, {
  "trades": {
    "model": "Trades_Information",
    "fields": {
      "orderCloseTime": "2019-03-19T16:20:56",
      "orderOpenPrice": "1.40000",
      "orderProfit": "75",
      "orderLots": "1.4"
    }
  }
}, {
  "trades": {
    "model": "Trades_Information",
    "fields": {
      "orderCloseTime": "2019-05-19T16:20:56",
      "orderOpenPrice": "1.40000",
      "orderProfit": "75",
      "orderLots": "1.4"
    }
  }
}, {
  "trades": {
    "model": "Trades_Information",
    "fields": {
      "orderCloseTime": "2019-11-19T16:20:56",
      "orderOpenPrice": "1.40000",
      "orderProfit": "75",
      "orderLots": "1.4"
    }
  }
}, {
  "trades": {
    "model": "Trades_Information",
    "fields": {
      "orderCloseTime": "2019-12-19T16:20:56",
      "orderOpenPrice": "1.40000",
      "orderProfit": "75",
      "orderLots": "1.4"
    }
  }
}];

// taken from https://stackoverflow.com/a/1985471/12354911
Array.prototype.rotate = (function() {
  var unshift = Array.prototype.unshift,
    splice = Array.prototype.splice;

  return function(count) {
    var len = this.length >>> 0,
      count = count >> 0;

    unshift.apply(this, splice.call(this, count % len, len));
    return this;
  };
})();

const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; // use this and keep ordering to later.
// since the size is clear create array with size
 // fill them with 0 to claculate easier
NetPipsMonth = Array(12).fill(0);
NetProfitMonth = Array(12).fill(0);
TotalVolumeMonth = Array(12).fill(0);
TotalTradesMonth = Array(12).fill(0);

   


tradesArr.forEach(t => {
  const fields = t.trades.fields;

  const ix = new Date(fields.orderCloseTime).getMonth(); // zero indexed month
  NetProfitMonth[ix] += +fields.orderProfit;
  TotalVolumeMonth[ix] += +fields.orderLots;
  // continute
});

// assume we are on may and we want may to be last item in the array
// Date().getMonth() gave us 4 (zero indexed) 
const rotation = -((12 - 4)-1); // we need to rotate 7 to the right
   
months.rotate(rotation);
NetProfitMonth.rotate(rotation);
TotalVolumeMonth.rotate(rotation);
console.log(months, NetProfitMonth, TotalVolumeMonth);
Eldar
  • 6,531
  • 2
  • 5
  • 25
  • I like this approach, but it seems that results are "delayed" by one month? E.g. march should have 150 profit, not 75. – Jonas Dec 22 '19 at 09:39
  • @Phanti my mistake. `getMonth` returns 0 indexed month. I assumed its 1 indexed. – Eldar Dec 22 '19 at 09:50
  • no worries, thank you very much. I will accept your answer over the other (which is also great), because yours is easier to understand for me as a JS rookie. – Jonas Dec 22 '19 at 09:54