fix: hyperliquid doesn't provide "average" in fetch_order

therefore this needs to be filled from trades to have a good price
 for market orders
This commit is contained in:
Matthias
2024-11-21 20:31:56 +01:00
parent cd83ed699c
commit 29b40d27e7
2 changed files with 68 additions and 1 deletions

View File

@@ -7,7 +7,8 @@ from freqtrade.constants import BuySell
from freqtrade.enums import MarginMode, TradingMode from freqtrade.enums import MarginMode, TradingMode
from freqtrade.exceptions import ExchangeError, OperationalException from freqtrade.exceptions import ExchangeError, OperationalException
from freqtrade.exchange import Exchange from freqtrade.exchange import Exchange
from freqtrade.exchange.exchange_types import FtHas from freqtrade.exchange.exchange_types import CcxtOrder, FtHas
from freqtrade.util.datetime_helpers import dt_from_ts
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -155,3 +156,26 @@ class Hyperliquid(Exchange):
except ExchangeError: except ExchangeError:
logger.warning(f"Could not update funding fees for {pair}.") logger.warning(f"Could not update funding fees for {pair}.")
return 0.0 return 0.0
def fetch_order(self, order_id: str, pair: str, params: dict | None = None) -> CcxtOrder:
order = super().fetch_order(order_id, pair, params)
if (
order["average"] is None
and order["status"] in ("canceled", "closed")
and order["filled"] > 0
):
# Hyperliquid does not fill the average price in the order response
# Fetch trades to calculate the average price to have the actual price
# the order was executed at
trades = self.get_trades_for_order(order_id, pair, since=dt_from_ts(order["timestamp"]))
if trades:
total_amount = sum(t["amount"] for t in trades)
order["average"] = (
sum(t["price"] * t["amount"] for t in trades) / total_amount
if total_amount
else None
)
return order

View File

@@ -372,3 +372,46 @@ def test_hyperliquid__lev_prep(default_conf, mocker):
assert api_mock.set_margin_mode.call_count == 1 assert api_mock.set_margin_mode.call_count == 1
api_mock.set_margin_mode.assert_called_with("isolated", "BTC/USDC:USDC", {"leverage": 19}) api_mock.set_margin_mode.assert_called_with("isolated", "BTC/USDC:USDC", {"leverage": 19})
def test_hyperliquid_fetch_order(default_conf_usdt, mocker):
default_conf_usdt["dry_run"] = False
api_mock = MagicMock()
api_mock.fetch_order = MagicMock(
return_value={
"id": "12345",
"symbol": "ETH/USDC:USDC",
"status": "closed",
"filled": 0.1,
"average": None,
"timestamp": 1630000000,
}
)
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
gtfo_mock = mocker.patch(
f"{EXMS}.get_trades_for_order",
return_value=[
{
"order_id": "12345",
"price": 1000,
"amount": 3,
"filled": 3,
"remaining": 0,
},
{
"order_id": "12345",
"price": 3000,
"amount": 1,
"filled": 1,
"remaining": 0,
},
],
)
exchange = get_patched_exchange(mocker, default_conf_usdt, api_mock, exchange="hyperliquid")
o = exchange.fetch_order("12345", "ETH/USDC:USDC")
# Uses weighted average
assert o["average"] == 1500
assert gtfo_mock.call_count == 1