fere-sdk 0.5.0.dev35__tar.gz → 0.5.0.dev37__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fere-sdk
3
- Version: 0.5.0.dev35
3
+ Version: 0.5.0.dev37
4
4
  Summary: Python SDK for the FereAI Gateway API
5
5
  Author-email: Fere AI <info@fere.ai>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fere-sdk"
3
- version = "0.5.0.dev35"
3
+ version = "0.5.0.dev37"
4
4
  description = "Python SDK for the FereAI Gateway API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -28,6 +28,10 @@ from .models import (
28
28
  PerpOpenRequest,
29
29
  PerpWithdrawRequest,
30
30
  SecurityCheckResponse,
31
+ SpotBuyRequest,
32
+ SpotCancelRequest,
33
+ SpotSellRequest,
34
+ SpotTpSlRequest,
31
35
  SwapRequest,
32
36
  TokenToCheck,
33
37
  WithdrawRequest,
@@ -384,10 +388,95 @@ class FereClient:
384
388
  )
385
389
  return await self._api.perp_withdraw(req, wait=True, timeout=timeout)
386
390
 
391
+ # ----------------------------------------------------------
392
+ # Spot (venue-neutral HyperCore spot)
393
+ # ----------------------------------------------------------
394
+
395
+ async def spot_hl_buy(
396
+ self,
397
+ asset: str,
398
+ size: float,
399
+ order_type: str = "market",
400
+ limit_price: float | None = None,
401
+ slippage_pct: float = 0.5,
402
+ tp_price: float | None = None,
403
+ sl_price: float | None = None,
404
+ timeout: int = DEFAULT_TIMEOUT,
405
+ ) -> dict:
406
+ """Buy a spot asset with USDC and wait for completion.
407
+
408
+ ``asset`` is a base symbol (USDC-quoted); ``size`` is the base-token
409
+ amount.
410
+ """
411
+ req = SpotBuyRequest(
412
+ asset=asset,
413
+ size=size,
414
+ order_type=order_type,
415
+ limit_price=limit_price,
416
+ slippage_pct=slippage_pct,
417
+ tp_price=tp_price,
418
+ sl_price=sl_price,
419
+ )
420
+ return await self._api.spot_hl_buy(req, wait=True, timeout=timeout)
421
+
422
+ async def spot_hl_sell(
423
+ self,
424
+ asset: str,
425
+ size: float | None = None,
426
+ order_type: str = "market",
427
+ limit_price: float | None = None,
428
+ slippage_pct: float = 0.5,
429
+ timeout: int = DEFAULT_TIMEOUT,
430
+ ) -> dict:
431
+ """Sell a held spot asset (omit size for full balance) and wait."""
432
+ req = SpotSellRequest(
433
+ asset=asset,
434
+ size=size,
435
+ order_type=order_type,
436
+ limit_price=limit_price,
437
+ slippage_pct=slippage_pct,
438
+ )
439
+ return await self._api.spot_hl_sell(req, wait=True, timeout=timeout)
440
+
441
+ async def spot_hl_set_tp_sl(
442
+ self,
443
+ asset: str,
444
+ tp_price: float | None = None,
445
+ sl_price: float | None = None,
446
+ size: float | None = None,
447
+ timeout: int = DEFAULT_TIMEOUT,
448
+ ) -> dict:
449
+ """Attach TP/SL sell triggers to a held spot asset and wait."""
450
+ req = SpotTpSlRequest(
451
+ asset=asset,
452
+ tp_price=tp_price,
453
+ sl_price=sl_price,
454
+ size=size,
455
+ )
456
+ return await self._api.spot_hl_set_tp_sl(req, wait=True, timeout=timeout)
457
+
458
+ async def spot_hl_cancel_order(
459
+ self,
460
+ asset: str,
461
+ order_id: int,
462
+ timeout: int = DEFAULT_TIMEOUT,
463
+ ) -> dict:
464
+ """Cancel an open spot order and wait for completion."""
465
+ req = SpotCancelRequest(asset=asset, order_id=order_id)
466
+ return await self._api.spot_hl_cancel_order(
467
+ req, wait=True, timeout=timeout
468
+ )
469
+
387
470
  # ----------------------------------------------------------
388
471
  # Read-only (pass-through)
389
472
  # ----------------------------------------------------------
390
473
 
474
+ async def get_spot_hl_markets(self, search_text: str | None = None) -> dict:
475
+ return await self._api.get_spot_hl_markets(search_text=search_text)
476
+
477
+ async def get_spot_hl_orders(self) -> dict:
478
+ return await self._api.get_spot_hl_orders()
479
+
391
480
  async def get_perp_markets(self, search_text: str | None = None) -> dict:
392
481
  return await self._api.get_perp_markets(search_text=search_text)
393
482
 
@@ -23,6 +23,10 @@ from .models import (
23
23
  PerpWithdrawRequest,
24
24
  SecurityCheckResponse,
25
25
  SecurityCheckSummary,
26
+ SpotBuyRequest,
27
+ SpotCancelRequest,
28
+ SpotSellRequest,
29
+ SpotTpSlRequest,
26
30
  SwapRequest,
27
31
  TaskResponse,
28
32
  TaskStatusResponse,
@@ -510,6 +514,65 @@ class FereAPI:
510
514
  "/v1/perp/withdraw", request.to_dict(), wait, timeout
511
515
  )
512
516
 
517
+ # ----------------------------------------------------------
518
+ # Spot (venue-neutral HyperCore spot)
519
+ # ----------------------------------------------------------
520
+
521
+ async def get_spot_hl_markets(self, search_text: str | None = None) -> dict:
522
+ """GET /v1/spot/markets"""
523
+ params = {}
524
+ if search_text:
525
+ params["search_text"] = search_text
526
+ return await self._authed_get("/v1/spot/markets", params=params)
527
+
528
+ async def get_spot_hl_orders(self) -> dict:
529
+ """GET /v1/spot/orders"""
530
+ return await self._authed_get("/v1/spot/orders")
531
+
532
+ async def spot_hl_buy(
533
+ self,
534
+ request: SpotBuyRequest,
535
+ wait: bool = False,
536
+ timeout: int = 120,
537
+ ) -> TaskResponse | dict:
538
+ """POST /v1/spot/buy"""
539
+ return await self._perp_task(
540
+ "/v1/spot/buy", request.to_dict(), wait, timeout
541
+ )
542
+
543
+ async def spot_hl_sell(
544
+ self,
545
+ request: SpotSellRequest,
546
+ wait: bool = False,
547
+ timeout: int = 120,
548
+ ) -> TaskResponse | dict:
549
+ """POST /v1/spot/sell"""
550
+ return await self._perp_task(
551
+ "/v1/spot/sell", request.to_dict(), wait, timeout
552
+ )
553
+
554
+ async def spot_hl_set_tp_sl(
555
+ self,
556
+ request: SpotTpSlRequest,
557
+ wait: bool = False,
558
+ timeout: int = 120,
559
+ ) -> TaskResponse | dict:
560
+ """POST /v1/spot/tp-sl"""
561
+ return await self._perp_task(
562
+ "/v1/spot/tp-sl", request.to_dict(), wait, timeout
563
+ )
564
+
565
+ async def spot_hl_cancel_order(
566
+ self,
567
+ request: SpotCancelRequest,
568
+ wait: bool = False,
569
+ timeout: int = 120,
570
+ ) -> TaskResponse | dict:
571
+ """POST /v1/spot/orders/cancel"""
572
+ return await self._perp_task(
573
+ "/v1/spot/orders/cancel", request.to_dict(), wait, timeout
574
+ )
575
+
513
576
  async def _perp_task(
514
577
  self,
515
578
  path: str,
@@ -14,6 +14,14 @@ from .perp_models import ( # noqa: E402,F401
14
14
  PerpWithdrawRequest,
15
15
  )
16
16
 
17
+ # Spot models live in their own module; re-exported here for back-compat.
18
+ from .spot_models import ( # noqa: E402,F401
19
+ SpotBuyRequest,
20
+ SpotCancelRequest,
21
+ SpotSellRequest,
22
+ SpotTpSlRequest,
23
+ )
24
+
17
25
  __all__ = [
18
26
  "TaskResponse",
19
27
  "TaskStatusResponse",
@@ -32,6 +40,10 @@ __all__ = [
32
40
  "PerpCancelRequest",
33
41
  "PerpFundRequest",
34
42
  "PerpWithdrawRequest",
43
+ "SpotBuyRequest",
44
+ "SpotSellRequest",
45
+ "SpotTpSlRequest",
46
+ "SpotCancelRequest",
35
47
  "TokenToCheck",
36
48
  "TokenSecurityResult",
37
49
  "SecurityCheckSummary",
@@ -0,0 +1,103 @@
1
+ """Venue-neutral HyperCore spot request models.
2
+
3
+ Kept in a dedicated module (per the team convention of giving new model groups
4
+ their own file) and re-exported from ``models.py``. Assets are base symbol only
5
+ and always USDC-quoted; ``size`` is the base-token amount.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+
12
+ __all__ = [
13
+ "SpotBuyRequest",
14
+ "SpotSellRequest",
15
+ "SpotTpSlRequest",
16
+ "SpotCancelRequest",
17
+ ]
18
+
19
+
20
+ @dataclass
21
+ class SpotBuyRequest:
22
+ """Buy a spot asset with USDC. size is the base-token amount."""
23
+
24
+ asset: str
25
+ size: float
26
+ order_type: str = "market"
27
+ limit_price: float | None = None
28
+ slippage_pct: float = 0.5
29
+ tp_price: float | None = None
30
+ sl_price: float | None = None
31
+ tp_is_market: bool = True
32
+ sl_is_market: bool = True
33
+
34
+ def to_dict(self) -> dict:
35
+ d: dict = {
36
+ "asset": self.asset,
37
+ "size": self.size,
38
+ "order_type": self.order_type,
39
+ "slippage_pct": self.slippage_pct,
40
+ "tp_is_market": self.tp_is_market,
41
+ "sl_is_market": self.sl_is_market,
42
+ }
43
+ if self.limit_price is not None:
44
+ d["limit_price"] = self.limit_price
45
+ if self.tp_price is not None:
46
+ d["tp_price"] = self.tp_price
47
+ if self.sl_price is not None:
48
+ d["sl_price"] = self.sl_price
49
+ return d
50
+
51
+
52
+ @dataclass
53
+ class SpotSellRequest:
54
+ asset: str
55
+ size: float | None = None
56
+ order_type: str = "market"
57
+ limit_price: float | None = None
58
+ slippage_pct: float = 0.5
59
+
60
+ def to_dict(self) -> dict:
61
+ d: dict = {
62
+ "asset": self.asset,
63
+ "order_type": self.order_type,
64
+ "slippage_pct": self.slippage_pct,
65
+ }
66
+ if self.size is not None:
67
+ d["size"] = self.size
68
+ if self.limit_price is not None:
69
+ d["limit_price"] = self.limit_price
70
+ return d
71
+
72
+
73
+ @dataclass
74
+ class SpotTpSlRequest:
75
+ asset: str
76
+ tp_price: float | None = None
77
+ sl_price: float | None = None
78
+ size: float | None = None
79
+ tp_is_market: bool = True
80
+ sl_is_market: bool = True
81
+
82
+ def to_dict(self) -> dict:
83
+ d: dict = {
84
+ "asset": self.asset,
85
+ "tp_is_market": self.tp_is_market,
86
+ "sl_is_market": self.sl_is_market,
87
+ }
88
+ if self.tp_price is not None:
89
+ d["tp_price"] = self.tp_price
90
+ if self.sl_price is not None:
91
+ d["sl_price"] = self.sl_price
92
+ if self.size is not None:
93
+ d["size"] = self.size
94
+ return d
95
+
96
+
97
+ @dataclass
98
+ class SpotCancelRequest:
99
+ asset: str
100
+ order_id: int
101
+
102
+ def to_dict(self) -> dict:
103
+ return {"asset": self.asset, "order_id": self.order_id}
File without changes