Hey, I have a list of inputs, that can be a buy or a sell.
I sort these according to being a sell or a buy and merge the ones with the same price(to be one unit with the sum of the amounts). Also I can keep them in one list with the same result.
What I want to do that with in mind of the order, I want the buys to hit out the sells, if the price is equal or lower, a transaction to happen sort of.
I can’t really wrap my head around it so far,
as I imagine I would need to go on item basis, like take the first from buy and sell, compare them -> make a decision that can be transaction and update the values/remove them -> or keep both of the items. But then on the next round I would need to keep the result of this in mind, and check on it first.
Any thoughts?
Sorry, for not giving context, so,
yes the other question is related, but this introduces a new problem, but that one was solved.
The problem:
I have this json:
{
"orders": [
{"command": "sell", "price": 100.003, "amount": 2.4},
{"command": "buy", "price": 90.394, "amount": 3.445},
{"command": "buy", "price": 89.394, "amount": 4.3},
{"command": "sell", "price": 100.013, "amount": 2.2},
{"command": "buy", "price": 90.15, "amount": 1.305},
{"command": "buy", "price": 90.394, "amount": 1.0},
{"command": "sell", "price": 90.394, "amount": 2.2}
]
}
and the expected output is:
{
"buy": [
{
"price": 90.394,
"volume": 2.245
},
{
"price": 90.15,
"volume": 1.305
},
{
"price": 89.394,
"volume": 4.3
},
],
"sell": [
{
"price": 100.003,
"volume": 2.4
},
{
"price": 100.013,
"volume": 2.2
}
]
}
all the sorting aside, as you see 7 goes in and 5 comes out.
the ones with the same price are added up or if there is a sell and a buy with the same price those take care of each other too.
I solved this by doing this after creating the orders:
my code here works on one list, and then i split that into the buy and sell lists for displaying, but if i split the 2 lists and then pass that list to this function we in the same spot
defp transactions(limit_orders) do
for order <- limit_orders do
Enum.reduce(
limit_orders,
order,
fn x, y ->
cond do
Decimal.cmp(x.price, y.price) == :eq and x.id != y.id and x.command == y.command ->
new_amount = Decimal.add(x.amount, y.amount)
y
|> Map.put(:amount, new_amount)
|> Map.put(:id, x.id)
Decimal.cmp(x.price, y.price) == :eq and x.command != y.command ->
case Decimal.cmp(x.amount, y.amount) do
:gt ->
new_amount = Decimal.sub(x.amount, y.amount)
Map.put(x, :amount, new_amount)
:lt ->
new_amount = Decimal.sub(y.amount, x.amount)
Map.put(y, :amount, new_amount)
:eq ->
nil
end
true ->
y
end
end
)
end
|> Enum.filter(&(!is_nil(&1)))
|> Enum.uniq_by(fn x -> x.id end)
end
The new problem:
let’s say I extend the previous order list with a few new orders:
{
"orders": [
{"command": "sell", "price": 100.003, "amount": 2.4},
{"command": "buy", "price": 90.394, "amount": 3.445},
{"command": "buy", "price": 89.394, "amount": 4.3},
{"command": "sell", "price": 100.013, "amount": 2.2},
{"command": "buy", "price": 90.15, "amount": 1.305},
{"command": "buy", "price": 90.394, "amount": 1.0},
{"command": "sell", "price": 90.394, "amount": 2.2},
new one below:
{"command": "sell", "price": 90.15, "amount": 3.4}
]
}
As you can see from the output of the previous one the the lowest buy price is higher than the lowest sell price 90.15 here. So that transaction should happen as well.
After that, we compare volume of 90.394 with amount of the sell command. volume of 90.394 is 2.245 and amount of 90.15 is 3.4. So that, we’ve amount left is 3.4 - 2.245 = 1.155 There is amount left. Then, this is partially matched! This command has to continue matching next buy price.
Continue next price, We compare 90.15 with 90.15 on Buy side. It is matched again. because the price on both side is equal. Let’s check the volume on buy side with the amount left which is 1.155 - 1.305 = -0.15. It means there is no amount left. And now volume on buy side would be 0.15.
So the expect output after this one is this:
{
"buy": [
{
"price": 90.15,
"volume": 0.15
},
{
"price": 89.394,
"volume": 4.3
},
],
"sell": [
{
"price": 100.003,
"volume": 2.4
},
{
"price": 100.013,
"volume": 2.2
}
]
}
my code in it’s current state puts out this:
{
"buy": [
{
"price": "90.394",
"volume": "2.245"
},
{
"price": "89.394",
"volume": "4.3"
}
],
"sell": [
{
"price": "90.15",
"volume": "2.095"
},
{
"price": "100.003",
"volume": "2.4"
},
{
"price": "100.013",
"volume": "2.2"
}
]
}
since it doesn’t match on higher buying price, only if it matches exactly.
I made another case where it would match if there is a higher buying price in a similar fashion to the matching price, but if i add other orders as well:
{
"orders": [
{"command": "sell", "price": 100.003, "amount": 2.4},
{"command": "buy", "price": 90.394, "amount": 3.445},
{"command": "buy", "price": 89.394, "amount": 4.3},
{"command": "sell", "price": 100.013, "amount": 2.2},
{"command": "buy", "price": 90.15, "amount": 1.305},
{"command": "buy", "price": 90.394, "amount": 1.0},
{"command": "sell", "price": 90.394, "amount": 2.2},
{"command": "sell", "price": 90.15, "amount": 3.4},
{"command": "buy", "price": 91.33, "amount": 1.8},
{"command": "buy", "price": 100.01, "amount": 4.0},
{"command": "sell", "price": 100.15, "amount": 3.8}
]
}
th3 3 bottom ones,
since my “design” doesn’t respect the order of the commands strictly put, it wont give the desired output:
{
"buy": [
{
"price": 100.01,
"volume": 1.6
},
{
"price": 91.33,
"volume": 1.8
},
{
"price": 90.15,
"volume": 0.15
},
{
"price": 89.394,
"volume": 4.3
},
],
"sell": [
{
"price": 100.013,
"volume": 2.2
},
{
"price": 100.15,
"volume": 3.8
}
]
}
because it would match on the exactly matching prices first