Convert data to OHLC (Open, High, Low, Close) in J

2019-01-20 04:08发布

问题:

Similar to create an OHLC data from Date, time, price using C#, how does one take the theory of converting basic trade data to OHLC (or Open, High, Low, Close) and apply it to this distinct case?

var data = [{
    "tid": 283945,
    "date": 1384934366,
    "amount": "0.08180000",
    "price": "501.30"
}, {
    "tid": 283947,
    "date": 1384934066,
    "amount": "0.06110000",
    "price": "490.66"
},
...
];

function convertToOHLC(data) {
    // What goes here?
}
convertToOHLC(data);

Here is the fiddle: https://jsfiddle.net/5dfjhnLw/

回答1:

This is a working function for converting the data to OHLC:

function convertToOHLC(data) {
    data.sort((a, b) => d3.ascending(a.date, b.date));
    var result = [];
    var format = d3.timeFormat("%Y-%m-%d");
    data.forEach(d => d.date = format(new Date(d.date * 1000)));
    var allDates = [...new Set(data.map(d => d.date))];
    allDates.forEach(d => {
        var tempObject = {};
        var filteredData = data.filter(e => e.date === d);
        tempObject.date = d;
        tempObject.open = filteredData[0].price;
        tempObject.close = filteredData[filteredData.length - 1].price;
        tempObject.high = d3.max(filteredData, e => e.price);
        tempObject.low = d3.min(filteredData, e => e.price);
        result.push(tempObject);
    });
    return result;
};

Here is your updated fiddle: https://jsfiddle.net/mg9v89r2/

Step by step explanation:

First, we sort the original data array by the dates:

data.sort((a, b) => d3.ascending(a.date, b.date));

That's an important step when we deal with open and close later.

After that, we convert the milliseconds to dates, as strings:

var format = d3.timeFormat("%Y-%m-%d");
data.forEach(d => d.date = format(new Date(d.date * 1000)));

Doing this, we can filter all objects belonging to a given day. First, we create an array with all different days in your data:

var allDates = [...new Set(data.map(d => d.date))];

For each day of that array, we will call a function that will populate an empty array, named results:

allDates.forEach(d => {
    var tempObject = {};
    var filteredData = data.filter(e => e.date === d);
    tempObject.date = d;
    tempObject.open = filteredData[0].price;
    tempObject.close = filteredData[filteredData.length - 1].price;
    tempObject.high = d3.max(filteredData, e => e.price);
    tempObject.low = d3.min(filteredData, e => e.price);
    result.push(tempObject);
});

In the above forEach, we create an empty object, and for each day in our allDates array, we filter the data:

var filteredData = data.filter(e => e.date === d);

And populate an temporary object with it:

var tempObject = {};
tempObject.date = d;
tempObject.open = filteredData[0].price;
tempObject.close = filteredData[filteredData.length - 1].price;
tempObject.high = d3.max(filteredData, e => e.price);
tempObject.low = d3.min(filteredData, e => e.price);

After each iteration, we push that temporary object into results:

result.push(tempObject);

Finally, we return results.

That huge data array in your fiddle, surprisingly, has only 2 days of data.