@@ -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,29 @@ 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+ func (api * ExchangeAPI ) MarketOrderSpot (coin string , size float64 , slippage * float64 ) (* PlaceOrderResponse , error ) {
124+ spotName := api .spotMeta [coin ].SpotName
125+ slpg := GetSlippage (slippage )
126+ isBuy := IsBuy (size )
127+ finalPx := api .SlippagePriceSpot (coin , isBuy , slpg )
128+ orderType := OrderType {
129+ Limit : & LimitOrderType {
130+ Tif : TifIoc ,
131+ },
132+ }
133+ orderRequest := OrderRequest {
134+ Coin : spotName ,
135+ IsBuy : isBuy ,
136+ Sz : math .Abs (size ),
137+ LimitPx : finalPx ,
138+ OrderType : orderType ,
139+ ReduceOnly : false ,
140+ }
141+ return api .OrderSpot (orderRequest , GroupingNa )
142+ }
143+
101144// Open a limit order.
102145// Order type can be Gtc, Ioc, Alo.
103146// Size determines the amount of the coin to buy/sell.
@@ -168,12 +211,39 @@ func (api *ExchangeAPI) Order(request OrderRequest, grouping Grouping) (*PlaceOr
168211 return api .BulkOrders ([]OrderRequest {request }, grouping )
169212}
170213
214+ // OrderSpot places a spot order
215+ func (api * ExchangeAPI ) OrderSpot (request OrderRequest , grouping Grouping ) (* PlaceOrderResponse , error ) {
216+ return api .BulkOrdersSpot ([]OrderRequest {request }, grouping )
217+ }
218+
171219// Place orders in bulk
172220// https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
173221func (api * ExchangeAPI ) BulkOrders (requests []OrderRequest , grouping Grouping ) (* PlaceOrderResponse , error ) {
174222 var wires []OrderWire
175223 for _ , req := range requests {
176- wires = append (wires , OrderRequestToWire (req , api .meta ))
224+ wires = append (wires , OrderRequestToWire (req , api .meta , false ))
225+ }
226+ timestamp := GetNonce ()
227+ action := OrderWiresToOrderAction (wires , grouping )
228+ v , r , s , err := api .SignL1Action (action , timestamp )
229+ if err != nil {
230+ api .debug ("Error signing L1 action: %s" , err )
231+ return nil , err
232+ }
233+ request := ExchangeRequest {
234+ Action : action ,
235+ Nonce : timestamp ,
236+ Signature : ToTypedSig (r , s , v ),
237+ VaultAddress : nil ,
238+ }
239+ return MakeUniversalRequest [PlaceOrderResponse ](api , request )
240+ }
241+
242+ // BulkOrdersSpot places spot orders
243+ func (api * ExchangeAPI ) BulkOrdersSpot (requests []OrderRequest , grouping Grouping ) (* PlaceOrderResponse , error ) {
244+ var wires []OrderWire
245+ for _ , req := range requests {
246+ wires = append (wires , OrderRequestToWire (req , api .spotMeta , true ))
177247 }
178248 timestamp := GetNonce ()
179249 action := OrderWiresToOrderAction (wires , grouping )
@@ -315,7 +385,7 @@ func (api *ExchangeAPI) getChainParams() (string, string) {
315385func (api * ExchangeAPI ) BuildBulkOrdersEIP712 (requests []OrderRequest , grouping Grouping ) (apitypes.TypedData , error ) {
316386 var wires []OrderWire
317387 for _ , req := range requests {
318- wires = append (wires , OrderRequestToWire (req , api .meta ))
388+ wires = append (wires , OrderRequestToWire (req , api .meta , false ))
319389 }
320390 timestamp := GetNonce ()
321391 action := OrderWiresToOrderAction (wires , grouping )
0 commit comments