fere-cli 0.4.0.dev35__tar.gz → 0.4.0.dev39__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.
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/PKG-INFO +2 -2
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/pyproject.toml +2 -2
- fere_cli-0.4.0.dev39/src/fere_cli/commands/spot_hl.py +229 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/commands/swap.py +1 -1
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/main.py +4 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/.gitignore +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/README.md +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/install.sh +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/__init__.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/async_util.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/banner.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/commands/__init__.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/commands/auth.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/commands/chat.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/commands/earn.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/commands/hooks.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/commands/limit_order.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/commands/perp.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/commands/portfolio.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/commands/utility.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/config.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/output.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/src/fere_cli/update.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/tests/test_install_sh.py +0 -0
- {fere_cli-0.4.0.dev35 → fere_cli-0.4.0.dev39}/tests/test_update.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fere-cli
|
|
3
|
-
Version: 0.4.0.
|
|
3
|
+
Version: 0.4.0.dev39
|
|
4
4
|
Summary: Terminal CLI for FereAI crypto trading and research
|
|
5
5
|
Author-email: Fere AI <info@fere.ai>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Requires-Python: >=3.10
|
|
8
8
|
Requires-Dist: click>=8.1
|
|
9
|
-
Requires-Dist: fere-sdk>=0.4.0.
|
|
9
|
+
Requires-Dist: fere-sdk>=0.4.0.dev39
|
|
10
10
|
Requires-Dist: httpx>=0.27
|
|
11
11
|
Requires-Dist: rich>=13.0
|
|
12
12
|
Provides-Extra: dev
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fere-cli"
|
|
3
|
-
version = "0.4.0.
|
|
3
|
+
version = "0.4.0.dev39"
|
|
4
4
|
description = "Terminal CLI for FereAI crypto trading and research"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
7
7
|
license = "MIT"
|
|
8
8
|
authors = [{ name = "Fere AI", email = "info@fere.ai" }]
|
|
9
9
|
dependencies = [
|
|
10
|
-
"fere-sdk>=0.4.0.
|
|
10
|
+
"fere-sdk>=0.4.0.dev39",
|
|
11
11
|
"httpx>=0.27",
|
|
12
12
|
"click>=8.1",
|
|
13
13
|
"rich>=13.0",
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"""Spot commands: fere spot (markets, orders, buy, sell, tp-sl, cancel).
|
|
2
|
+
|
|
3
|
+
Venue-neutral HyperCore spot trading. Assets are base symbol only (always
|
|
4
|
+
USDC-quoted); ``size`` is the base-token amount.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from ..async_util import async_command, get_client, is_tty
|
|
13
|
+
from ..output import print_error, print_success
|
|
14
|
+
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@click.group()
|
|
19
|
+
def spot_hl():
|
|
20
|
+
"""Trade HyperCore spot assets (buy, sell, tp-sl)."""
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@spot_hl.command()
|
|
25
|
+
@click.option("--search", default=None, help="Filter the asset universe.")
|
|
26
|
+
@click.pass_context
|
|
27
|
+
@async_command
|
|
28
|
+
async def markets(ctx, search):
|
|
29
|
+
"""List the tradable spot market universe."""
|
|
30
|
+
try:
|
|
31
|
+
client = await get_client(ctx)
|
|
32
|
+
data = await client.get_spot_hl_markets(search_text=search)
|
|
33
|
+
await client.close()
|
|
34
|
+
print_success(data)
|
|
35
|
+
except click.ClickException:
|
|
36
|
+
raise
|
|
37
|
+
except Exception as e:
|
|
38
|
+
print_error(str(e))
|
|
39
|
+
raise SystemExit(1)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@spot_hl.command()
|
|
43
|
+
@click.pass_context
|
|
44
|
+
@async_command
|
|
45
|
+
async def orders(ctx):
|
|
46
|
+
"""List open spot orders (incl. TP/SL triggers)."""
|
|
47
|
+
try:
|
|
48
|
+
client = await get_client(ctx)
|
|
49
|
+
data = await client.get_spot_hl_orders()
|
|
50
|
+
await client.close()
|
|
51
|
+
print_success(data)
|
|
52
|
+
except click.ClickException:
|
|
53
|
+
raise
|
|
54
|
+
except Exception as e:
|
|
55
|
+
print_error(str(e))
|
|
56
|
+
raise SystemExit(1)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@spot_hl.command()
|
|
60
|
+
@click.option("--asset", required=True, help="Base asset symbol, e.g. HYPE.")
|
|
61
|
+
@click.option("--size", required=True, type=float, help="Base-token amount.")
|
|
62
|
+
@click.option(
|
|
63
|
+
"--order-type",
|
|
64
|
+
default="market",
|
|
65
|
+
type=click.Choice(["market", "limit"]),
|
|
66
|
+
)
|
|
67
|
+
@click.option("--limit-price", default=None, type=float)
|
|
68
|
+
@click.option("--slippage-pct", default=0.5, type=float)
|
|
69
|
+
@click.option("--tp-price", default=None, type=float, help="Take-profit.")
|
|
70
|
+
@click.option("--sl-price", default=None, type=float, help="Stop-loss.")
|
|
71
|
+
@click.option(
|
|
72
|
+
"--timeout", default=120, type=int, help="Wait timeout (seconds)."
|
|
73
|
+
)
|
|
74
|
+
@click.option("-y", "--yes", is_flag=True, help="Skip confirmation.")
|
|
75
|
+
@click.pass_context
|
|
76
|
+
@async_command
|
|
77
|
+
async def buy(
|
|
78
|
+
ctx,
|
|
79
|
+
asset,
|
|
80
|
+
size,
|
|
81
|
+
order_type,
|
|
82
|
+
limit_price,
|
|
83
|
+
slippage_pct,
|
|
84
|
+
tp_price,
|
|
85
|
+
sl_price,
|
|
86
|
+
timeout,
|
|
87
|
+
yes,
|
|
88
|
+
):
|
|
89
|
+
"""Buy a spot asset with USDC."""
|
|
90
|
+
if not yes and is_tty():
|
|
91
|
+
click.echo(f"Buy {size} {asset} ({order_type})")
|
|
92
|
+
if not click.confirm("Proceed?"):
|
|
93
|
+
raise SystemExit(0)
|
|
94
|
+
try:
|
|
95
|
+
client = await get_client(ctx)
|
|
96
|
+
with console.status("Buying..."):
|
|
97
|
+
result = await client.spot_hl_buy(
|
|
98
|
+
asset=asset,
|
|
99
|
+
size=size,
|
|
100
|
+
order_type=order_type,
|
|
101
|
+
limit_price=limit_price,
|
|
102
|
+
slippage_pct=slippage_pct,
|
|
103
|
+
tp_price=tp_price,
|
|
104
|
+
sl_price=sl_price,
|
|
105
|
+
timeout=timeout,
|
|
106
|
+
)
|
|
107
|
+
await client.close()
|
|
108
|
+
print_success(result)
|
|
109
|
+
except click.ClickException:
|
|
110
|
+
raise
|
|
111
|
+
except Exception as e:
|
|
112
|
+
print_error(str(e))
|
|
113
|
+
raise SystemExit(1)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@spot_hl.command()
|
|
117
|
+
@click.option("--asset", required=True, help="Base asset symbol to sell.")
|
|
118
|
+
@click.option(
|
|
119
|
+
"--size",
|
|
120
|
+
default=None,
|
|
121
|
+
type=float,
|
|
122
|
+
help="Base-token amount; omit to sell the full balance.",
|
|
123
|
+
)
|
|
124
|
+
@click.option(
|
|
125
|
+
"--order-type",
|
|
126
|
+
default="market",
|
|
127
|
+
type=click.Choice(["market", "limit"]),
|
|
128
|
+
)
|
|
129
|
+
@click.option("--limit-price", default=None, type=float)
|
|
130
|
+
@click.option("--slippage-pct", default=0.5, type=float)
|
|
131
|
+
@click.option(
|
|
132
|
+
"--timeout", default=120, type=int, help="Wait timeout (seconds)."
|
|
133
|
+
)
|
|
134
|
+
@click.option("-y", "--yes", is_flag=True, help="Skip confirmation.")
|
|
135
|
+
@click.pass_context
|
|
136
|
+
@async_command
|
|
137
|
+
async def sell(
|
|
138
|
+
ctx, asset, size, order_type, limit_price, slippage_pct, timeout, yes
|
|
139
|
+
):
|
|
140
|
+
"""Sell a held spot asset back to USDC."""
|
|
141
|
+
if not yes and is_tty():
|
|
142
|
+
amt = f"{size}" if size is not None else "full balance"
|
|
143
|
+
click.echo(f"Sell {amt} {asset} ({order_type})")
|
|
144
|
+
if not click.confirm("Proceed?"):
|
|
145
|
+
raise SystemExit(0)
|
|
146
|
+
try:
|
|
147
|
+
client = await get_client(ctx)
|
|
148
|
+
with console.status("Selling..."):
|
|
149
|
+
result = await client.spot_hl_sell(
|
|
150
|
+
asset=asset,
|
|
151
|
+
size=size,
|
|
152
|
+
order_type=order_type,
|
|
153
|
+
limit_price=limit_price,
|
|
154
|
+
slippage_pct=slippage_pct,
|
|
155
|
+
timeout=timeout,
|
|
156
|
+
)
|
|
157
|
+
await client.close()
|
|
158
|
+
print_success(result)
|
|
159
|
+
except click.ClickException:
|
|
160
|
+
raise
|
|
161
|
+
except Exception as e:
|
|
162
|
+
print_error(str(e))
|
|
163
|
+
raise SystemExit(1)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@spot_hl.command(name="tp-sl")
|
|
167
|
+
@click.option("--asset", required=True, help="Held asset symbol to protect.")
|
|
168
|
+
@click.option("--tp-price", default=None, type=float, help="Take-profit.")
|
|
169
|
+
@click.option("--sl-price", default=None, type=float, help="Stop-loss.")
|
|
170
|
+
@click.option(
|
|
171
|
+
"--size",
|
|
172
|
+
default=None,
|
|
173
|
+
type=float,
|
|
174
|
+
help="Base amount; omit for the full held balance.",
|
|
175
|
+
)
|
|
176
|
+
@click.option(
|
|
177
|
+
"--timeout", default=120, type=int, help="Wait timeout (seconds)."
|
|
178
|
+
)
|
|
179
|
+
@click.pass_context
|
|
180
|
+
@async_command
|
|
181
|
+
async def tp_sl(ctx, asset, tp_price, sl_price, size, timeout):
|
|
182
|
+
"""Attach reduce-side TP/SL sell triggers to a held spot asset."""
|
|
183
|
+
if tp_price is None and sl_price is None:
|
|
184
|
+
print_error("Provide at least one of --tp-price / --sl-price")
|
|
185
|
+
raise SystemExit(1)
|
|
186
|
+
try:
|
|
187
|
+
client = await get_client(ctx)
|
|
188
|
+
with console.status("Setting TP/SL..."):
|
|
189
|
+
result = await client.spot_hl_set_tp_sl(
|
|
190
|
+
asset=asset,
|
|
191
|
+
tp_price=tp_price,
|
|
192
|
+
sl_price=sl_price,
|
|
193
|
+
size=size,
|
|
194
|
+
timeout=timeout,
|
|
195
|
+
)
|
|
196
|
+
await client.close()
|
|
197
|
+
print_success(result)
|
|
198
|
+
except click.ClickException:
|
|
199
|
+
raise
|
|
200
|
+
except Exception as e:
|
|
201
|
+
print_error(str(e))
|
|
202
|
+
raise SystemExit(1)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@spot_hl.command()
|
|
206
|
+
@click.option("--asset", required=True, help="Asset symbol of the order.")
|
|
207
|
+
@click.option(
|
|
208
|
+
"--order-id", required=True, type=int, help="Venue order id (oid)."
|
|
209
|
+
)
|
|
210
|
+
@click.option(
|
|
211
|
+
"--timeout", default=120, type=int, help="Wait timeout (seconds)."
|
|
212
|
+
)
|
|
213
|
+
@click.pass_context
|
|
214
|
+
@async_command
|
|
215
|
+
async def cancel(ctx, asset, order_id, timeout):
|
|
216
|
+
"""Cancel an open spot order by its venue order id."""
|
|
217
|
+
try:
|
|
218
|
+
client = await get_client(ctx)
|
|
219
|
+
with console.status("Cancelling order..."):
|
|
220
|
+
result = await client.spot_hl_cancel_order(
|
|
221
|
+
asset=asset, order_id=order_id, timeout=timeout
|
|
222
|
+
)
|
|
223
|
+
await client.close()
|
|
224
|
+
print_success(result)
|
|
225
|
+
except click.ClickException:
|
|
226
|
+
raise
|
|
227
|
+
except Exception as e:
|
|
228
|
+
print_error(str(e))
|
|
229
|
+
raise SystemExit(1)
|
|
@@ -78,7 +78,7 @@ async def swap(
|
|
|
78
78
|
timeout,
|
|
79
79
|
yes,
|
|
80
80
|
):
|
|
81
|
-
"""Execute a token swap
|
|
81
|
+
"""Execute a gasless, cross-chain token swap (bridging built in)."""
|
|
82
82
|
# Confirmation prompt (TTY only)
|
|
83
83
|
if not yes and is_tty() and not dryrun:
|
|
84
84
|
click.echo(
|
|
@@ -12,6 +12,7 @@ from .commands.hooks import hooks
|
|
|
12
12
|
from .commands.limit_order import limit_order
|
|
13
13
|
from .commands.perp import perp
|
|
14
14
|
from .commands.portfolio import holdings, notifications, wallets
|
|
15
|
+
from .commands.spot_hl import spot_hl
|
|
15
16
|
from .commands.swap import swap
|
|
16
17
|
from .commands.utility import chains, config, status
|
|
17
18
|
from .update import maybe_check_for_updates
|
|
@@ -94,6 +95,9 @@ cli.add_command(earn)
|
|
|
94
95
|
# Perp (venue-neutral perpetual futures)
|
|
95
96
|
cli.add_command(perp)
|
|
96
97
|
|
|
98
|
+
# Spot (venue-neutral HyperCore spot)
|
|
99
|
+
cli.add_command(spot_hl, name="spot-hl")
|
|
100
|
+
|
|
97
101
|
# Utility
|
|
98
102
|
cli.add_command(chains)
|
|
99
103
|
cli.add_command(status)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|