Обработка массива JSON
Есть задача написать дневник на основе входящих сделок в формате JSON. При get запросе получаем массив такого типа
[
{
"symbol": "ORANGE",
"id": 479640841,
"side": "SELL",
"price": "10",
"qty": "2",
"time": 1633371930706
},
{
"symbol": "ORANGE",
"id": 479640941,
"side": "SELL",
"price": "10",
"qty": "1",
"time": 1633371930899
},
{
"symbol": "ORANGE",
"id": 479640952,
"side": "BUY",
"price": "20",
"qty": "3",
"time": 1633371940488
},
{
"symbol": "APPLE",
"id": 193964871,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956055821
},
{
"symbol": "APPLE",
"id": 193964907,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956058086
},
{
"symbol": "APPLE",
"id": 193964908,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956058086
},
{
"symbol": "APPLE",
"id": 193965481,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956074364
},
{
"symbol": "APPLE",
"id": 193967061,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956209504
},
{
"symbol": "APPLE",
"id": 193967211,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956222593
},
{
"symbol": "APPLE",
"id": 193968864,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956403438
},
{
"symbol": "APPLE",
"id": 193969405,
"side": "SELL",
"price": "20",
"qty": "70",
"time": 1633956450685
}
]
Надо написать конструктор, который будет считывать массив объектов и выдавать готовые ордера в другом массиве такого типа
let orders = [
{
symbol: "ORANGE", // конструктор находит в массиве первую сделку ORANGE, записывает в свойство ее id, а потом ищет последующие сделки с ORANGE, пока open (количество апельсинов в позиции) не будет равно 0, будет прибавлять (если SELL) или убавлять (BUY) свойство open
id: 479640841, // id первой сделки по ORANGE
side: "SHORT", // если первой сделкой идет SELL, тогда это позиция в SHORT. Последкющие SELL прибавляют open, а BUY убавляют.
open: 0, // пока размер позиции не равен нулю, считать, что позиция еще не закрыта (2+1-3=0)
profit: -30, // высчитывается профит сделки ("(2*10 + 1*10) - 3*20")
//3*20 это последняя сделка BUY, qty:3 - количество апельсинов. price: 20 - по какой цене выкуплено (BUY)
volume: 3, // количество проданных в залог апельсинов (суммируются все сделки с SELL)
openTime: 1633371930706, // время первой сделки по ORANGE (SELL 2, "id": 479640841)
closedTime: 1633371940488, // время последней сделки по ORANGE (BUY 3, "id": 479640952)
},
{
symbol: "APPLE", // конструктор находит в массиве первую сделку APPLE, записывает в свойство ее id, а потом ищет последующие сделки с APPLE, пока open (количество яблок в позиции) не будет равно 0, будет прибавлять (если BUY) или убавлять (SELL) свойство open
id: 193964871, // id первой сделки по APPLE
side: "LONG", // если первой сделкой идет BUY, тогда это позиция в LONG
open: 0, // пока размер позиции не равен нулю, считать, что позиция еще не закрыта (10+10+10+10+10+10+10-70=0)
profit: 390, // высчитывается профит сделки ("70*20 - (10*15 + 10*15 + 10*15 + 10*15 + 10*15 + 10*15 + 10*15)")
//70*20 это последняя сделка SELL, qty:70 - количество яблок. price: 20 - по какой цене продано (если SELL, или куплено, если BUY)
volume: 70, // количество купленных яблок (суммируются все сделки с BUY)
openTime: 1633956055821, // время первой сделки по APPLE (BUY 10, "id": 193964871)
closedTime: 1633956450685, // время последней сделки по APPLE (SELL 70, "id": 193969405)
},
];
Можно, конечно, сделать все бесконечными if else и циклами, но хотелось бы найти более лаконичное решение. |
Пишешь функцию, в ней цикл for (let str of array) и прописываешь все нужные switch case в ней
|
Цитата:
volume: "70" откуда 70? |
Цитата:
Volume 3 это сумма "id": 479640841 "id": 479640941 (2+1). Так как первым в массиве orange идёт sell - это сделка типа short и суммируется набор позиции со свойством SELL Volume 70 это сумма первых семи объектов APPLE (10+10+10+10+10+10+10), так как первый объект по apple со свойством BUY это набор позиции в long и суммируются объекты со свойством BUY |
Redline,
не осилил))) [{SELL : 2} , {BUY : 1}, {BUY : 3}] суммируется набор позиции со свойством SELL ? с чем суммировать SELL, если SELL в наборе всего 1 раз |
Если прям на пальцах, допустим ты покупаешь яблоки на рынке, чтобы перепродать дороже. цель - набрать 70 яблок.
Ходишь по магазину, покупаешь по 10, по 20 штук где дешевле и набираешь 70. Чтобы завершить сделку, теперь тебе надо продать эти 70 яблок. Все эти действия это и есть массив JSON Так вот когда у тебя яблок не осталось можно считать сделку завершенной и подвести итоги. Сколько яблок было, какую прибыль получил и тд |
Ошибка в массиве, сейчас исправлю
|
[{SELL : 2} , {SELL : 1}, {BUY : 3}]
В данном примере это Orange сделка типа short. То есть ты берешь 3 (2+1) апельсина в долг и сразу продаешь в надежде, что цена упадет, выкупишь дешевле, а разницу возьмешь себе. Возможно необязательная инфа. Так, для понимания что в массиве происходит |
Цитата:
|
Да, верно. Массив подгонялся для понимания. По факту там крипта)
|
Redline,
медитируйте ...)))
<body>
<script>
let json = [{
"symbol": "ORANGE",
"id": 479640841,
"side": "SELL",
"price": "10",
"qty": "2",
"time": 1633371930706
},
{
"symbol": "ORANGE",
"id": 479640941,
"side": "SELL",
"price": "10",
"qty": "1",
"time": 1633371930899
},
{
"symbol": "ORANGE",
"id": 479640952,
"side": "BUY",
"price": "20",
"qty": "3",
"time": 1633371940488
},
{
"symbol": "APPLE",
"id": 193964871,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956055821
},
{
"symbol": "APPLE",
"id": 193964907,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956058086
},
{
"symbol": "APPLE",
"id": 193964908,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956058086
},
{
"symbol": "APPLE",
"id": 193965481,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956074364
},
{
"symbol": "APPLE",
"id": 193967061,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956209504
},
{
"symbol": "APPLE",
"id": 193967211,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956222593
},
{
"symbol": "APPLE",
"id": 193968864,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956403438
},
{
"symbol": "APPLE",
"id": 193969405,
"side": "SELL",
"price": "20",
"qty": "70",
"time": 1633956450685
}
];
let obj = json.reduce((ob, {
symbol,
id,
side,
price,
qty,
time
}) => {
side = side === "BUY" ? "LONG" : "SHORT";
if(!ob[symbol]) ob[symbol] = {
symbol,
id,
side,
open: 0,
profit: 0,
volume: 0,
openTime: time
};
ob[symbol].closedTime = time;
let period = ob[symbol].side;
price *= qty;
if (period === side) {
ob[symbol].open += +qty;
ob[symbol].volume += +qty;
ob[symbol].profit += price;
} else {
if (side === "LONG") ob[symbol].profit -= price;
else ob[symbol].profit = price - ob[symbol].profit;
ob[symbol].open -= qty;
}
return ob
}, {});
document.write(`<pre>${JSON.stringify(obj,'',1)}</pre>`, )
</script>
</body>
|
Еще забыл дополнить. Конструктор не будет знать заранее какой symbol он будет принимать. Он должен просто брать первый попавшийся symbol, и записывать все аналогичные символы, пока open не будет равен 0.
Если на пути попадается другой символ, то это уже начало новой сделки |
Благодарю, выглядит отлично:thanks:
|
При добавлении нового элемента APPLE код работает с уже имеющимся в массиве APPLE, а не создает новый. Нужно научить код присваивать уникальный идентификатор к каждому объекту правильно понимаю?
В примере ниже я добавил еще одну сделку 10 BUY и 10 SELL
<body>
<script>
let json = [{
"symbol": "ORANGE",
"id": 479640841,
"side": "SELL",
"price": "10",
"qty": "2",
"time": 1633371930706
},
{
"symbol": "ORANGE",
"id": 479640941,
"side": "SELL",
"price": "10",
"qty": "1",
"time": 1633371930899
},
{
"symbol": "ORANGE",
"id": 479640952,
"side": "BUY",
"price": "20",
"qty": "3",
"time": 1633371940488
},
{
"symbol": "APPLE",
"id": 193964871,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956055821
},
{
"symbol": "APPLE",
"id": 193964907,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956058086
},
{
"symbol": "APPLE",
"id": 193964908,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956058086
},
{
"symbol": "APPLE",
"id": 193965481,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956074364
},
{
"symbol": "APPLE",
"id": 193967061,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956209504
},
{
"symbol": "APPLE",
"id": 193967211,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956222593
},
{
"symbol": "APPLE",
"id": 193968864,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956403438
},
{
"symbol": "APPLE",
"id": 193969405,
"side": "SELL",
"price": "20",
"qty": "70",
"time": 1633956450685
},
{
"symbol": "APPLE",
"id": 193968888,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956403438
},
{
"symbol": "APPLE",
"id": 193969444,
"side": "SELL",
"price": "20",
"qty": "10",
"time": 1633956450685
}
];
let obj = json.reduce((ob, {
symbol,
id,
side,
price,
qty,
time
}) => {
side = side === "BUY" ? "LONG" : "SHORT";
if(!ob[symbol]) ob[symbol] = {
symbol,
id,
side,
open: 0,
profit: 0,
volume: 0,
openTime: time
};
ob[symbol].closedTime = time;
let period = ob[symbol].side;
price *= qty;
if (period === side) {
ob[symbol].open += +qty;
ob[symbol].volume += +qty;
ob[symbol].profit += price;
} else {
if (side === "LONG") ob[symbol].profit -= price;
else ob[symbol].profit = price - ob[symbol].profit;
ob[symbol].open -= qty;
}
return ob
}, {});
document.write(`<pre>${JSON.stringify(obj,'',1)}</pre>`, )
</script>
</body>
|
Redline,
Цитата:
<body>
<script>
let json = [{
"symbol": "ORANGE",
"id": 479640841,
"side": "SELL",
"price": "10",
"qty": "2",
"time": 1633371930706
},
{
"symbol": "ORANGE",
"id": 479640941,
"side": "SELL",
"price": "10",
"qty": "1",
"time": 1633371930899
},
{
"symbol": "ORANGE",
"id": 479640952,
"side": "BUY",
"price": "20",
"qty": "3",
"time": 1633371940488
},
{
"symbol": "APPLE",
"id": 193964871,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956055821
},
{
"symbol": "APPLE",
"id": 193964907,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956058086
},
{
"symbol": "APPLE",
"id": 193964908,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956058086
},
{
"symbol": "APPLE",
"id": 193965481,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956074364
},
{
"symbol": "APPLE",
"id": 193967061,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956209504
},
{
"symbol": "APPLE",
"id": 193967211,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956222593
},
{
"symbol": "APPLE",
"id": 193968864,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956403438
},
{
"symbol": "APPLE",
"id": 193969405,
"side": "SELL",
"price": "20",
"qty": "70",
"time": 1633956450685
},
{
"symbol": "APPLE",
"id": 193968888,
"side": "BUY",
"price": "15",
"qty": "10",
"time": 1633956403438
},
{
"symbol": "APPLE",
"id": 193969444,
"side": "SELL",
"price": "20",
"qty": "10",
"time": 1633956450685
}
];
let arr = json.reduce((ar, {
symbol,
id,
side,
price,
qty,
time
}) => {
side = side === "BUY" ? "LONG" : "SHORT";
let e = ar.at(-1);
if(!e || !e.open) {
e = {
symbol,
id,
side,
open: 0,
profit: 0,
volume: 0,
openTime: time
};
ar.push(e);
};
e.closedTime = time;
let period = e.side;
price *= qty;
if (period === side) {
e.open += +qty;
e.volume += +qty;
e.profit += price;
} else {
if (side === "LONG") e.profit -= price;
else e.profit = price - e.profit;
e.open -= qty;
}
return ar
}, []);
document.write(`<pre>${JSON.stringify(arr,'',1)}</pre>`, )
</script>
</body>
|
Благодарю вас еще раз. Да, в нюансах я ошибся :-?
|
Вложений: 2
Доработал код, появилась проблема с большими числами. JS неправильно обрабатывает числа, я это помню. Код будет работать с большими массивами. Как добавить точность коду?
там где volume 0,0999999 должно быть 0,1 а второй массив не должен вообще появляться |
|
Вложений: 2
добавил tofixed, но на 6 и 10 итерации прибавления никакой реакции. Будто он не видит этот метод
|
Redline,
сделайте округление когда уже массив сформирован
ordersBook = ordersBook.map(ordersBookItem => {
ordersBookItem.open = +ordersBookItem.open.toFixed(1); // округляет неточности
ordersBookItem.volume = +ordersBookItem.volume.toFixed(1);
ordersBookItem.profitOpen = +ordersBookItem.profitOpen.toFixed(1);
ordersBookItem.profitClosed = +ordersBookItem.profitClosed.toFixed(1);
ordersBookItem.profit = +ordersBookItem.profit.toFixed(1);
return ordersBookItem;
});
|
| Часовой пояс GMT +3, время: 00:50. |