Fee correction¶
Fees?¶
When using unmanaged trade signals in a spot market, it's good to think about the fees. When we buy 1 BTC, it doesn't mean we get 1 BTC. The exchange will deduct its portion of the fees from either your traded amount or your wallet, leaving us with a little less than 1 BTC. Let's say we pay 0.2% fee. After buying 1 BTC, we get 0.998 BTC and the exchange takes 0.002. Now, if we execute a sell order of 1 BTC, it might not execute unless we have a little extra BTC in the wallet.
Consequences¶
Not taking fees into consideration can have a domino effect. Let's say we are scripting a market making bot. The bot has 3 slots. It places 3 buy orders of 1 BTC each and they are all filled. The exchange deducts the fees of 0.006 BTC and we are left with 2.994 BTC. The script executes 3 sell orders, dropping the position to 1.994 BTC, then 0.994 BTC. The third sell of 1 BTC oversells by 0.006 BTC - that's the buy fees that were never accounted for. Add the 0.002 BTC sell fee on top (deducted from the sell amount), and the bot ends up with an unintended short of 0.008 BTC.
Solving the issue¶
Although this is a very inconvenient issue, it's also very easily solved. When we want to exit the position (sell what we have bought) we use the PlaceExitPositionOrder command. This will place an order with the exact amount you have set. If you are using the TradeAmount() to buy and sell, you will sell more than you got. So to solve this, you need to use the GetPositionAmount() for exits to be able to sell the correct amount.
Tip
Taking the position size into account when selling what you bought will also eliminate issues when the position is considered open after a partially filled order.
Examples¶
Implementation¶
Let's do this "the wrong way" first:
-- Our buy order, when we want to accumulate a position:
entryOrder = PlaceBuyOrder(entryPrice, 1)
-- Our sell order, when we want to distribute our position:
exitOrder = PlaceSellOrder(exitPrice, 1)
In the above example, we do not account for fees - or rather, don't account for the actual position size at all. If we have excess assets in our wallet and we are doing this, we are slowly draining that asset until we hit a point where selling 1 coin isn't possible anymore.
Here's how we fix that:
-- Our buy order, as previously:
entryOrder = PlaceBuyOrder(entryPrice, 1)
-- This time when we are selling, we
-- want to sell the position, not 1:
local posAmount = GetPositionAmount()
exitOrder = PlaceSellOrder(exitPrice, posAmount)
This time, we are selling what we got from the buy order, and will not drain any excess in the long-term. Not all exchanges deduct the fees from the amount you buy, but always doing it this way will eliminate potential problems in the future.
We can also use the PlaceExitPositionOrder that does this automatically for us:
This command essentially does the same as we did previously by grabbing the position amount for our sell order.