@@ -36,6 +36,7 @@ type ExchangeAPI struct {
3636 address string
3737 baseEndpoint string
3838 meta map [string ]AssetInfo
39+ spotMeta map [string ]AssetInfo
3940}
4041
4142// NewExchangeAPI creates a new default ExchangeAPI.
@@ -54,6 +55,14 @@ func NewExchangeAPI(isMainnet bool) *ExchangeAPI {
5455 api .debug ("Error building meta map: %s" , err )
5556 }
5657 api .meta = meta
58+
59+ spotMeta , err := api .infoAPI .BuildSpotMetaMap ()
60+ if err != nil {
61+ api .SetDebugActive ()
62+ api .debug ("Error building spot meta map: %s" , err )
63+ }
64+ api .spotMeta = spotMeta
65+
5766 return & api
5867}
5968
@@ -71,6 +80,17 @@ func (api *ExchangeAPI) SlippagePrice(coin string, isBuy bool, slippage float64)
7180 return CalculateSlippage (isBuy , marketPx , slippage )
7281}
7382
83+ // SlippagePriceSpot is a helper function to calculate the slippage price for a spot coin.
84+ func (api * ExchangeAPI ) SlippagePriceSpot (coin string , isBuy bool , slippage float64 ) float64 {
85+ marketPx , err := api .infoAPI .GetSpotMarketPx (coin )
86+ if err != nil {
87+ api .debug ("Error getting market price: %s" , err )
88+ return 0.0
89+ }
90+ slippagePrice := CalculateSlippage (isBuy , marketPx , slippage )
91+ return slippagePrice
92+ }
93+
7494// Open a market order.
7595// Limit order with TIF=IOC and px=market price * (1 +- slippage).
7696// Size determines the amount of the coin to buy/sell.
@@ -98,6 +118,34 @@ func (api *ExchangeAPI) MarketOrder(coin string, size float64, slippage *float64
98118 return api .Order (orderRequest , GroupingNa )
99119}
100120
121+ // MarketOrderSpot is a market order for a spot coin.
122+ // It is used to buy/sell a spot coin.
123+ // Limit order with TIF=IOC and px=market price * (1 +- slippage).
124+ // Size determines the amount of the coin to buy/sell.
125+ //
126+ // MarketOrderSpot("HYPE", 0.1, nil) // Buy 0.1 HYPE
127+ // MarketOrderSpot("HYPE", -0.1, nil) // Sell 0.1 HYPE
128+ // MarketOrderSpot("HYPE", 0.1, &slippage) // Buy 0.1 HYPE with slippage
129+ func (api * ExchangeAPI ) MarketOrderSpot (coin string , size float64 , slippage * float64 ) (* PlaceOrderResponse , error ) {
130+ slpg := GetSlippage (slippage )
131+ isBuy := IsBuy (size )
132+ finalPx := api .SlippagePriceSpot (coin , isBuy , slpg )
133+ orderType := OrderType {
134+ Limit : & LimitOrderType {
135+ Tif : TifIoc ,
136+ },
137+ }
138+ orderRequest := OrderRequest {
139+ Coin : coin ,
140+ IsBuy : isBuy ,
141+ Sz : math .Abs (size ),
142+ LimitPx : finalPx ,
143+ OrderType : orderType ,
144+ ReduceOnly : false ,
145+ }
146+ return api .OrderSpot (orderRequest , GroupingNa )
147+ }
148+
101149// Open a limit order.
102150// Order type can be Gtc, Ioc, Alo.
103151// Size determines the amount of the coin to buy/sell.
@@ -165,15 +213,26 @@ func (api *ExchangeAPI) ClosePosition(coin string) (*PlaceOrderResponse, error)
165213
166214// Place single order
167215func (api * ExchangeAPI ) Order (request OrderRequest , grouping Grouping ) (* PlaceOrderResponse , error ) {
168- return api .BulkOrders ([]OrderRequest {request }, grouping )
216+ return api .BulkOrders ([]OrderRequest {request }, grouping , false )
217+ }
218+
219+ // OrderSpot places a spot order
220+ func (api * ExchangeAPI ) OrderSpot (request OrderRequest , grouping Grouping ) (* PlaceOrderResponse , error ) {
221+ return api .BulkOrders ([]OrderRequest {request }, grouping , true )
169222}
170223
171224// Place orders in bulk
172225// https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
173- func (api * ExchangeAPI ) BulkOrders (requests []OrderRequest , grouping Grouping ) (* PlaceOrderResponse , error ) {
226+ func (api * ExchangeAPI ) BulkOrders (requests []OrderRequest , grouping Grouping , isSpot bool ) (* PlaceOrderResponse , error ) {
174227 var wires []OrderWire
228+ var meta map [string ]AssetInfo
229+ if isSpot {
230+ meta = api .spotMeta
231+ } else {
232+ meta = api .meta
233+ }
175234 for _ , req := range requests {
176- wires = append (wires , OrderRequestToWire (req , api . meta ))
235+ wires = append (wires , OrderRequestToWire (req , meta , isSpot ))
177236 }
178237 timestamp := GetNonce ()
179238 action := OrderWiresToOrderAction (wires , grouping )
@@ -283,7 +342,7 @@ func (api *ExchangeAPI) Withdraw(destination string, amount float64) (*WithdrawR
283342 action := WithdrawAction {
284343 Type : "withdraw3" ,
285344 Destination : destination ,
286- Amount : FloatToWire (amount , & SZ_DECIMALS ),
345+ Amount : FloatToWire (amount , PERP_MAX_DECIMALS , SZ_DECIMALS ),
287346 Time : nonce ,
288347 }
289348 signatureChainID , chainType := api .getChainParams ()
@@ -315,7 +374,7 @@ func (api *ExchangeAPI) getChainParams() (string, string) {
315374func (api * ExchangeAPI ) BuildBulkOrdersEIP712 (requests []OrderRequest , grouping Grouping ) (apitypes.TypedData , error ) {
316375 var wires []OrderWire
317376 for _ , req := range requests {
318- wires = append (wires , OrderRequestToWire (req , api .meta ))
377+ wires = append (wires , OrderRequestToWire (req , api .meta , false ))
319378 }
320379 timestamp := GetNonce ()
321380 action := OrderWiresToOrderAction (wires , grouping )
0 commit comments