mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-15 00:36:56 +08:00
fix: enable full-size Claw402 autopilot trading
This commit is contained in:
@@ -265,9 +265,9 @@ func (s *Server) createDefaultStrategies(userID string, lang string) error {
|
|||||||
c.RiskControl.MaxPositions = 2
|
c.RiskControl.MaxPositions = 2
|
||||||
c.RiskControl.BTCETHMaxLeverage = 10
|
c.RiskControl.BTCETHMaxLeverage = 10
|
||||||
c.RiskControl.AltcoinMaxLeverage = 10
|
c.RiskControl.AltcoinMaxLeverage = 10
|
||||||
c.RiskControl.BTCETHMaxPositionValueRatio = 1.0
|
c.RiskControl.BTCETHMaxPositionValueRatio = 10.0
|
||||||
c.RiskControl.AltcoinMaxPositionValueRatio = 1.0
|
c.RiskControl.AltcoinMaxPositionValueRatio = 10.0
|
||||||
c.RiskControl.MaxMarginUsage = 0.35
|
c.RiskControl.MaxMarginUsage = 1.0
|
||||||
c.RiskControl.MinConfidence = 78
|
c.RiskControl.MinConfidence = 78
|
||||||
c.RiskControl.MinRiskRewardRatio = 3.0
|
c.RiskControl.MinRiskRewardRatio = 3.0
|
||||||
c.Indicators.Klines.PrimaryTimeframe = "15m"
|
c.Indicators.Klines.PrimaryTimeframe = "15m"
|
||||||
|
|||||||
@@ -54,12 +54,17 @@ func TestCreateDefaultStrategiesUsesOneReadyToRunClaw402Preset(t *testing.T) {
|
|||||||
if trendCfg.CoinSource.SourceType != "vergex_signal" || trendCfg.CoinSource.VergexLimit != 10 || trendCfg.CoinSource.VergexMarketType != "all" {
|
if trendCfg.CoinSource.SourceType != "vergex_signal" || trendCfg.CoinSource.VergexLimit != 10 || trendCfg.CoinSource.VergexMarketType != "all" {
|
||||||
t.Fatalf("default strategy should use the Claw402/Vergex all-market signal ranking, got %+v", trendCfg.CoinSource)
|
t.Fatalf("default strategy should use the Claw402/Vergex all-market signal ranking, got %+v", trendCfg.CoinSource)
|
||||||
}
|
}
|
||||||
if trendCfg.CoinSource.UseAI500 || trendCfg.RiskControl.MaxPositions > 2 || trendCfg.RiskControl.MaxMarginUsage > 0.45 {
|
if trendCfg.CoinSource.UseAI500 || trendCfg.RiskControl.MaxPositions > 2 {
|
||||||
t.Fatalf("default strategy should be low-risk Claw402/Vergex native, got coin=%+v risk=%+v", trendCfg.CoinSource, trendCfg.RiskControl)
|
t.Fatalf("default strategy should be Claw402/Vergex native with at most two positions, got coin=%+v risk=%+v", trendCfg.CoinSource, trendCfg.RiskControl)
|
||||||
}
|
}
|
||||||
if trendCfg.RiskControl.BTCETHMaxLeverage != 10 || trendCfg.RiskControl.AltcoinMaxLeverage != 10 {
|
if trendCfg.RiskControl.BTCETHMaxLeverage != 10 || trendCfg.RiskControl.AltcoinMaxLeverage != 10 {
|
||||||
t.Fatalf("default strategy should use 10x leverage for all Claw402 opens, got risk=%+v", trendCfg.RiskControl)
|
t.Fatalf("default strategy should use 10x leverage for all Claw402 opens, got risk=%+v", trendCfg.RiskControl)
|
||||||
}
|
}
|
||||||
|
if trendCfg.RiskControl.BTCETHMaxPositionValueRatio != 10 ||
|
||||||
|
trendCfg.RiskControl.AltcoinMaxPositionValueRatio != 10 ||
|
||||||
|
trendCfg.RiskControl.MaxMarginUsage != 1.0 {
|
||||||
|
t.Fatalf("default strategy should use full-size 10x notional for Claw402 opens, got risk=%+v", trendCfg.RiskControl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDefaultStrategiesMigratesLegacyPresetsWithoutOverridingActiveCustom(t *testing.T) {
|
func TestCreateDefaultStrategiesMigratesLegacyPresetsWithoutOverridingActiveCustom(t *testing.T) {
|
||||||
|
|||||||
@@ -100,6 +100,20 @@ func TestLeverageFallback(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClaw402XyzAllowsFullTenXNotional(t *testing.T) {
|
||||||
|
decision := Decision{
|
||||||
|
Symbol: "xyz:SP500",
|
||||||
|
Action: "open_long",
|
||||||
|
Leverage: 10,
|
||||||
|
PositionSizeUSD: 306.8,
|
||||||
|
StopLoss: 95,
|
||||||
|
TakeProfit: 120,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validateDecision(&decision, 30.68, 10, 10, 10.0, 10.0); err != nil {
|
||||||
|
t.Fatalf("xyz TradeFi Claw402 full 10x notional should pass validation: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// contains checks if string contains substring (helper function)
|
// contains checks if string contains substring (helper function)
|
||||||
func contains(s, substr string) bool {
|
func contains(s, substr string) bool {
|
||||||
|
|||||||
@@ -1017,9 +1017,9 @@ func GetDefaultStrategyConfig(lang string) StrategyConfig {
|
|||||||
MaxPositions: 2, // Max 2 instruments simultaneously (CODE ENFORCED)
|
MaxPositions: 2, // Max 2 instruments simultaneously (CODE ENFORCED)
|
||||||
BTCETHMaxLeverage: 10, // BTC/ETH exchange leverage (AI guided)
|
BTCETHMaxLeverage: 10, // BTC/ETH exchange leverage (AI guided)
|
||||||
AltcoinMaxLeverage: 10, // TradeFi exchange leverage (AI guided)
|
AltcoinMaxLeverage: 10, // TradeFi exchange leverage (AI guided)
|
||||||
BTCETHMaxPositionValueRatio: 1.0, // Claw402 default: same cap across assets
|
BTCETHMaxPositionValueRatio: 10.0, // Claw402 full-size 10x notional: equity × 10
|
||||||
AltcoinMaxPositionValueRatio: 1.0, // Claw402 default: same cap across assets
|
AltcoinMaxPositionValueRatio: 10.0, // Claw402 full-size 10x notional: equity × 10
|
||||||
MaxMarginUsage: 0.35, // Max 35% margin usage (CODE ENFORCED)
|
MaxMarginUsage: 1.0, // Claw402 Autopilot intentionally uses full margin when opening
|
||||||
MinPositionSize: 12, // Min 12 USDT per position (CODE ENFORCED)
|
MinPositionSize: 12, // Min 12 USDT per position (CODE ENFORCED)
|
||||||
MinRiskRewardRatio: 3.0, // Min 3:1 profit/loss ratio (AI guided)
|
MinRiskRewardRatio: 3.0, // Min 3:1 profit/loss ratio (AI guided)
|
||||||
MinConfidence: 78, // Min 78% confidence (AI guided)
|
MinConfidence: 78, // Min 78% confidence (AI guided)
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ func TestApplyAutopilotFullSizeOpenForClaw402(t *testing.T) {
|
|||||||
cfg.CoinSource.SourceType = "vergex_signal"
|
cfg.CoinSource.SourceType = "vergex_signal"
|
||||||
cfg.RiskControl.BTCETHMaxLeverage = 10
|
cfg.RiskControl.BTCETHMaxLeverage = 10
|
||||||
cfg.RiskControl.AltcoinMaxLeverage = 10
|
cfg.RiskControl.AltcoinMaxLeverage = 10
|
||||||
cfg.RiskControl.BTCETHMaxPositionValueRatio = 1
|
cfg.RiskControl.BTCETHMaxPositionValueRatio = 10
|
||||||
cfg.RiskControl.AltcoinMaxPositionValueRatio = 1
|
cfg.RiskControl.AltcoinMaxPositionValueRatio = 10
|
||||||
|
|
||||||
at := &AutoTrader{config: AutoTraderConfig{StrategyConfig: &cfg}}
|
at := &AutoTrader{config: AutoTraderConfig{StrategyConfig: &cfg}}
|
||||||
decision := &kernel.Decision{
|
decision := &kernel.Decision{
|
||||||
@@ -27,8 +27,8 @@ func TestApplyAutopilotFullSizeOpenForClaw402(t *testing.T) {
|
|||||||
if decision.Leverage != 10 {
|
if decision.Leverage != 10 {
|
||||||
t.Fatalf("expected leverage to be forced to 10x, got %dx", decision.Leverage)
|
t.Fatalf("expected leverage to be forced to 10x, got %dx", decision.Leverage)
|
||||||
}
|
}
|
||||||
if decision.PositionSizeUSD != 29.8 {
|
if decision.PositionSizeUSD != 298 {
|
||||||
t.Fatalf("expected position size to use full notional 29.8, got %.2f", decision.PositionSizeUSD)
|
t.Fatalf("expected position size to use full 10x notional 298, got %.2f", decision.PositionSizeUSD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,13 +58,14 @@ func (t *HyperliquidTrader) OpenLong(symbol string, quantity float64, leverage i
|
|||||||
// Check if this is an xyz dex asset
|
// Check if this is an xyz dex asset
|
||||||
isXyz := strings.HasPrefix(coin, "xyz:")
|
isXyz := strings.HasPrefix(coin, "xyz:")
|
||||||
|
|
||||||
// Set leverage (skip for xyz dex as it may not support leverage adjustment)
|
// Set leverage before order placement. Hyperliquid supports leverage
|
||||||
if !isXyz {
|
// updates for HIP-3/XYZ perps as well; skipping this left reused accounts
|
||||||
if err := t.SetLeverage(symbol, leverage); err != nil {
|
// at whatever leverage they had previously selected (for example 20x).
|
||||||
|
if err := t.SetLeverage(symbol, leverage); err != nil {
|
||||||
|
if !isXyz {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
logger.Warnf(" ⚠ Failed to set leverage for xyz dex asset %s: %v", coin, err)
|
||||||
logger.Infof(" ℹ xyz dex asset %s - using default leverage", coin)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current price (for market order)
|
// Get current price (for market order)
|
||||||
@@ -130,13 +131,14 @@ func (t *HyperliquidTrader) OpenShort(symbol string, quantity float64, leverage
|
|||||||
// Check if this is an xyz dex asset
|
// Check if this is an xyz dex asset
|
||||||
isXyz := strings.HasPrefix(coin, "xyz:")
|
isXyz := strings.HasPrefix(coin, "xyz:")
|
||||||
|
|
||||||
// Set leverage (skip for xyz dex)
|
// Set leverage before order placement. Hyperliquid supports leverage
|
||||||
if !isXyz {
|
// updates for HIP-3/XYZ perps as well; skipping this left reused accounts
|
||||||
if err := t.SetLeverage(symbol, leverage); err != nil {
|
// at whatever leverage they had previously selected (for example 20x).
|
||||||
|
if err := t.SetLeverage(symbol, leverage); err != nil {
|
||||||
|
if !isXyz {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
logger.Warnf(" ⚠ Failed to set leverage for xyz dex asset %s: %v", coin, err)
|
||||||
logger.Infof(" ℹ xyz dex asset %s - using default leverage", coin)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current price
|
// Get current price
|
||||||
@@ -1029,11 +1031,15 @@ func (t *HyperliquidTrader) SetTakeProfit(symbol string, positionSide string, qu
|
|||||||
func (t *HyperliquidTrader) PlaceLimitOrder(req *types.LimitOrderRequest) (*types.LimitOrderResult, error) {
|
func (t *HyperliquidTrader) PlaceLimitOrder(req *types.LimitOrderRequest) (*types.LimitOrderResult, error) {
|
||||||
coin := convertSymbolToHyperliquid(req.Symbol)
|
coin := convertSymbolToHyperliquid(req.Symbol)
|
||||||
|
|
||||||
// Set leverage if specified and not xyz dex
|
// Set leverage if specified.
|
||||||
isXyz := strings.HasPrefix(coin, "xyz:")
|
isXyz := strings.HasPrefix(coin, "xyz:")
|
||||||
if req.Leverage > 0 && !isXyz {
|
if req.Leverage > 0 {
|
||||||
if err := t.SetLeverage(req.Symbol, req.Leverage); err != nil {
|
if err := t.SetLeverage(req.Symbol, req.Leverage); err != nil {
|
||||||
logger.Warnf("[Hyperliquid] Failed to set leverage: %v", err)
|
if !isXyz {
|
||||||
|
logger.Warnf("[Hyperliquid] Failed to set leverage: %v", err)
|
||||||
|
} else {
|
||||||
|
logger.Warnf("[Hyperliquid] Failed to set xyz leverage for %s: %v", coin, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
Check,
|
Check,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
Copy,
|
Copy,
|
||||||
|
Download,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
Loader2,
|
Loader2,
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
@@ -237,6 +238,7 @@ export function HyperliquidWalletConnect({
|
|||||||
const [balanceError, setBalanceError] = useState('')
|
const [balanceError, setBalanceError] = useState('')
|
||||||
const [agentInfo, setAgentInfo] = useState<HyperliquidAgentInfo | null>(null)
|
const [agentInfo, setAgentInfo] = useState<HyperliquidAgentInfo | null>(null)
|
||||||
const [agentInfoLoading, setAgentInfoLoading] = useState(false)
|
const [agentInfoLoading, setAgentInfoLoading] = useState(false)
|
||||||
|
const [hasWalletProvider, setHasWalletProvider] = useState(false)
|
||||||
const text = useMemo(
|
const text = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
title: language === 'zh' ? 'Hyperliquid 钱包' : 'Hyperliquid Wallet',
|
title: language === 'zh' ? 'Hyperliquid 钱包' : 'Hyperliquid Wallet',
|
||||||
@@ -278,10 +280,22 @@ export function HyperliquidWalletConnect({
|
|||||||
language === 'zh'
|
language === 'zh'
|
||||||
? 'Hyperliquid 不允许重复使用同一个 Agent,续期会生成一个新的 Agent 并以 180 天有效期授权,然后自动更新 NOFX 保存的私钥(需登录)。'
|
? 'Hyperliquid 不允许重复使用同一个 Agent,续期会生成一个新的 Agent 并以 180 天有效期授权,然后自动更新 NOFX 保存的私钥(需登录)。'
|
||||||
: 'Hyperliquid forbids reusing an agent, so renewal creates a new agent approved for 180 days, then updates the stored key in NOFX (sign-in required).',
|
: 'Hyperliquid forbids reusing an agent, so renewal creates a new agent approved for 180 days, then updates the stored key in NOFX (sign-in required).',
|
||||||
|
noWalletTitle:
|
||||||
|
language === 'zh' ? '未检测到 EVM 钱包' : 'No EVM wallet detected',
|
||||||
|
noWalletDetail:
|
||||||
|
language === 'zh'
|
||||||
|
? '先安装 Rabby 或 MetaMask,创建或导入钱包,然后回到这里连接 Hyperliquid。'
|
||||||
|
: 'Install Rabby or MetaMask, create or import a wallet, then return here to connect Hyperliquid.',
|
||||||
|
installRabby: language === 'zh' ? '安装 Rabby' : 'Install Rabby',
|
||||||
|
installMetaMask: language === 'zh' ? '安装 MetaMask' : 'Install MetaMask',
|
||||||
}),
|
}),
|
||||||
[language]
|
[language]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHasWalletProvider(Boolean(getPreferredWalletProvider()))
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
saveState(state)
|
saveState(state)
|
||||||
}, [state])
|
}, [state])
|
||||||
@@ -960,6 +974,37 @@ export function HyperliquidWalletConnect({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{!state.mainWallet && !hasWalletProvider && (
|
||||||
|
<div className="rounded-xl border border-nofx-gold/20 bg-nofx-gold/5 p-3">
|
||||||
|
<div className="text-sm font-semibold text-zinc-100">
|
||||||
|
{text.noWalletTitle}
|
||||||
|
</div>
|
||||||
|
<p className="mt-1 text-xs leading-5 text-nofx-text-muted">
|
||||||
|
{text.noWalletDetail}
|
||||||
|
</p>
|
||||||
|
<div className="mt-3 flex flex-wrap gap-2">
|
||||||
|
<a
|
||||||
|
href="https://rabby.io/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center gap-2 rounded-lg border border-white/10 bg-white/[0.04] px-3 py-2 text-xs font-semibold text-zinc-200 hover:border-white/20 hover:bg-white/[0.07]"
|
||||||
|
>
|
||||||
|
<Download className="h-3.5 w-3.5" />
|
||||||
|
{text.installRabby}
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://metamask.io/download/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center gap-2 rounded-lg border border-white/10 bg-white/[0.04] px-3 py-2 text-xs font-semibold text-zinc-200 hover:border-white/20 hover:bg-white/[0.07]"
|
||||||
|
>
|
||||||
|
<ExternalLink className="h-3.5 w-3.5" />
|
||||||
|
{text.installMetaMask}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="rounded-xl border border-white/10 bg-black/25 p-3 space-y-2 text-xs">
|
<div className="rounded-xl border border-white/10 bg-black/25 p-3 space-y-2 text-xs">
|
||||||
{state.mainWallet && (
|
{state.mainWallet && (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ import { useNavigate } from 'react-router-dom'
|
|||||||
import {
|
import {
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
ArrowRight,
|
ArrowRight,
|
||||||
|
CircleDollarSign,
|
||||||
|
Download,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
Copy,
|
Copy,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
|
KeyRound,
|
||||||
Loader2,
|
Loader2,
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
ShieldCheck,
|
ShieldCheck,
|
||||||
@@ -67,6 +70,114 @@ async function copyText(value: string, label: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function BeginnerHyperliquidGuide({
|
||||||
|
hasInjectedWallet,
|
||||||
|
}: {
|
||||||
|
hasInjectedWallet: boolean
|
||||||
|
}) {
|
||||||
|
const steps = [
|
||||||
|
{
|
||||||
|
title: 'Prepare an EVM wallet',
|
||||||
|
detail: hasInjectedWallet
|
||||||
|
? 'Wallet extension detected. Unlock it, then connect below.'
|
||||||
|
: 'Install Rabby or MetaMask, create or import a wallet, then return here.',
|
||||||
|
icon: Wallet,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Open Hyperliquid',
|
||||||
|
detail:
|
||||||
|
'Use the same wallet on Hyperliquid. Deposit USDC there as trading collateral.',
|
||||||
|
icon: CircleDollarSign,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Authorize NOFX',
|
||||||
|
detail:
|
||||||
|
'Back in NOFX, approve the Agent and builder fee. NOFX stores the Agent key, not your main wallet key.',
|
||||||
|
icon: KeyRound,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rounded-xl border border-nofx-gold/20 bg-[linear-gradient(180deg,rgba(240,185,11,0.1),rgba(0,0,0,0.16))] p-4">
|
||||||
|
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-semibold text-white">
|
||||||
|
New to Hyperliquid?
|
||||||
|
</div>
|
||||||
|
<p className="mt-1 text-xs leading-5 text-nofx-text-muted">
|
||||||
|
Start here if you do not have a trading wallet or have never used
|
||||||
|
Hyperliquid before.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`w-fit rounded-full px-2.5 py-1 text-[11px] font-semibold ${
|
||||||
|
hasInjectedWallet
|
||||||
|
? 'bg-emerald-500/10 text-emerald-300'
|
||||||
|
: 'bg-nofx-gold/10 text-nofx-gold'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{hasInjectedWallet ? 'Wallet detected' : 'Wallet needed'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 grid gap-3">
|
||||||
|
{steps.map((step, index) => {
|
||||||
|
const Icon = step.icon
|
||||||
|
return (
|
||||||
|
<div key={step.title} className="flex gap-3">
|
||||||
|
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg border border-white/10 bg-black/25 text-nofx-gold">
|
||||||
|
<Icon className="h-3.5 w-3.5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-semibold text-zinc-100">
|
||||||
|
{index + 1}. {step.title}
|
||||||
|
</div>
|
||||||
|
<p className="mt-0.5 text-xs leading-5 text-nofx-text-muted">
|
||||||
|
{step.detail}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 flex flex-wrap gap-2">
|
||||||
|
{!hasInjectedWallet ? (
|
||||||
|
<>
|
||||||
|
<a
|
||||||
|
href="https://rabby.io/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center gap-2 rounded-lg border border-white/10 bg-white/[0.04] px-3 py-2 text-xs font-semibold text-zinc-200 hover:border-white/20 hover:bg-white/[0.07]"
|
||||||
|
>
|
||||||
|
<Download className="h-3.5 w-3.5" />
|
||||||
|
Install Rabby
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://metamask.io/download/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center gap-2 rounded-lg border border-white/10 bg-white/[0.04] px-3 py-2 text-xs font-semibold text-zinc-200 hover:border-white/20 hover:bg-white/[0.07]"
|
||||||
|
>
|
||||||
|
<ExternalLink className="h-3.5 w-3.5" />
|
||||||
|
MetaMask
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
<a
|
||||||
|
href="https://app.hyperliquid.xyz/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center gap-2 rounded-lg bg-nofx-gold px-3 py-2 text-xs font-bold text-black hover:bg-yellow-400"
|
||||||
|
>
|
||||||
|
Open Hyperliquid
|
||||||
|
<ExternalLink className="h-3.5 w-3.5" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function AutopilotLaunchPanel({
|
export function AutopilotLaunchPanel({
|
||||||
models,
|
models,
|
||||||
exchanges,
|
exchanges,
|
||||||
@@ -83,8 +194,16 @@ export function AutopilotLaunchPanel({
|
|||||||
const [walletLoading, setWalletLoading] = useState(false)
|
const [walletLoading, setWalletLoading] = useState(false)
|
||||||
const [launching, setLaunching] = useState(false)
|
const [launching, setLaunching] = useState(false)
|
||||||
const [refreshing, setRefreshing] = useState(false)
|
const [refreshing, setRefreshing] = useState(false)
|
||||||
|
const [hasInjectedWallet, setHasInjectedWallet] = useState(false)
|
||||||
const isZh = language === 'zh'
|
const isZh = language === 'zh'
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHasInjectedWallet(
|
||||||
|
typeof window !== 'undefined' &&
|
||||||
|
Boolean((window as Window & { ethereum?: unknown }).ethereum)
|
||||||
|
)
|
||||||
|
}, [])
|
||||||
|
|
||||||
const claw402Model = useMemo(
|
const claw402Model = useMemo(
|
||||||
() =>
|
() =>
|
||||||
models.find(
|
models.find(
|
||||||
@@ -470,13 +589,16 @@ export function AutopilotLaunchPanel({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div id="hyperliquid-quick-connect">
|
<div className="space-y-4">
|
||||||
<HyperliquidWalletConnect
|
<BeginnerHyperliquidGuide hasInjectedWallet={hasInjectedWallet} />
|
||||||
language={isZh ? 'zh' : 'en'}
|
<div id="hyperliquid-quick-connect">
|
||||||
isLoggedIn={isLoggedIn}
|
<HyperliquidWalletConnect
|
||||||
variant="inline"
|
language={isZh ? 'zh' : 'en'}
|
||||||
onSaved={refreshEverything}
|
isLoggedIn={isLoggedIn}
|
||||||
/>
|
variant="inline"
|
||||||
|
onSaved={refreshEverything}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import {
|
|||||||
ArrowRight,
|
ArrowRight,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
CircleDollarSign,
|
CircleDollarSign,
|
||||||
|
Download,
|
||||||
|
ExternalLink,
|
||||||
KeyRound,
|
KeyRound,
|
||||||
ShieldCheck,
|
ShieldCheck,
|
||||||
Wallet,
|
Wallet,
|
||||||
@@ -106,6 +108,59 @@ export function TraderLaunchGuestPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section className="grid gap-5 rounded-2xl border border-white/10 bg-[#0A0D12] p-5 md:grid-cols-[0.78fr_1.22fr] md:p-6">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-semibold uppercase tracking-[0.18em] text-nofx-gold">
|
||||||
|
No trading wallet yet?
|
||||||
|
</div>
|
||||||
|
<p className="mt-3 text-sm leading-6 text-zinc-500">
|
||||||
|
NOFX does not need your main-wallet private key. Install or unlock
|
||||||
|
an EVM wallet, fund Hyperliquid with USDC, then authorize the NOFX
|
||||||
|
Agent after sign-in.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid gap-3 lg:grid-cols-3">
|
||||||
|
<a
|
||||||
|
href="https://rabby.io/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="group rounded-xl border border-white/10 bg-white/[0.03] p-4 transition hover:border-nofx-gold/30 hover:bg-nofx-gold/[0.04]"
|
||||||
|
>
|
||||||
|
<Download className="mb-3 h-4 w-4 text-nofx-gold" />
|
||||||
|
<div className="font-semibold text-white">Install Rabby</div>
|
||||||
|
<p className="mt-2 text-sm leading-6 text-zinc-500">
|
||||||
|
Create or import an EVM wallet before connecting to Hyperliquid.
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://metamask.io/download/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="group rounded-xl border border-white/10 bg-white/[0.03] p-4 transition hover:border-nofx-gold/30 hover:bg-nofx-gold/[0.04]"
|
||||||
|
>
|
||||||
|
<ExternalLink className="mb-3 h-4 w-4 text-nofx-gold" />
|
||||||
|
<div className="font-semibold text-white">MetaMask</div>
|
||||||
|
<p className="mt-2 text-sm leading-6 text-zinc-500">
|
||||||
|
Already use MetaMask? Unlock it, then continue setup inside
|
||||||
|
NOFX.
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://app.hyperliquid.xyz/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="group rounded-xl border border-nofx-gold/20 bg-nofx-gold/10 p-4 transition hover:bg-nofx-gold/15"
|
||||||
|
>
|
||||||
|
<ExternalLink className="mb-3 h-4 w-4 text-nofx-gold" />
|
||||||
|
<div className="font-semibold text-white">Open Hyperliquid</div>
|
||||||
|
<p className="mt-2 text-sm leading-6 text-zinc-400">
|
||||||
|
Deposit USDC there. Trading funds stay in your Hyperliquid
|
||||||
|
account.
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section className="grid gap-4 rounded-2xl border border-white/10 bg-[#0A0D12] p-5 md:grid-cols-[0.72fr_1.28fr] md:p-6">
|
<section className="grid gap-4 rounded-2xl border border-white/10 bg-[#0A0D12] p-5 md:grid-cols-[0.72fr_1.28fr] md:p-6">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm font-semibold uppercase tracking-[0.18em] text-nofx-gold">
|
<div className="text-sm font-semibold uppercase tracking-[0.18em] text-nofx-gold">
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ const profileOptions: Array<{
|
|||||||
topN: 5,
|
topN: 5,
|
||||||
timeframe: '1h',
|
timeframe: '1h',
|
||||||
bars: 30,
|
bars: 30,
|
||||||
margin: 0.25,
|
margin: 1.0,
|
||||||
promptZh:
|
promptZh:
|
||||||
'稳健模式:只有 Claw402 榜单方向、Signal Lab、成本/清算热力图和原始 K 线同时支持时才开仓;信号冲突时等待。',
|
'稳健模式:只有 Claw402 榜单方向、Signal Lab、成本/清算热力图和原始 K 线同时支持时才开仓;信号冲突时等待。',
|
||||||
promptEn:
|
promptEn:
|
||||||
@@ -169,7 +169,7 @@ const profileOptions: Array<{
|
|||||||
topN: 5,
|
topN: 5,
|
||||||
timeframe: '15m',
|
timeframe: '15m',
|
||||||
bars: 30,
|
bars: 30,
|
||||||
margin: 0.35,
|
margin: 1.0,
|
||||||
promptZh:
|
promptZh:
|
||||||
'均衡模式:优先交易 Claw402 排名靠前且 Signal Lab 与 K 线同向的标的;用清算热力图确定止损和止盈区域。',
|
'均衡模式:优先交易 Claw402 排名靠前且 Signal Lab 与 K 线同向的标的;用清算热力图确定止损和止盈区域。',
|
||||||
promptEn:
|
promptEn:
|
||||||
@@ -187,7 +187,7 @@ const profileOptions: Array<{
|
|||||||
topN: 8,
|
topN: 8,
|
||||||
timeframe: '5m',
|
timeframe: '5m',
|
||||||
bars: 50,
|
bars: 50,
|
||||||
margin: 0.5,
|
margin: 1.0,
|
||||||
promptZh:
|
promptZh:
|
||||||
'进取模式:可以更快跟随 Claw402 强信号,但必须用 Signal Lab 二次确认,用热力图区避开拥挤清算位,止损必须明确。',
|
'进取模式:可以更快跟随 Claw402 强信号,但必须用 Signal Lab 二次确认,用热力图区避开拥挤清算位,止损必须明确。',
|
||||||
promptEn:
|
promptEn:
|
||||||
@@ -287,10 +287,10 @@ function defaultRisk(risk?: Partial<RiskControlConfig>): RiskControlConfig {
|
|||||||
btc_eth_max_leverage: leverage,
|
btc_eth_max_leverage: leverage,
|
||||||
altcoin_max_leverage: leverage,
|
altcoin_max_leverage: leverage,
|
||||||
btc_eth_max_position_value_ratio:
|
btc_eth_max_position_value_ratio:
|
||||||
risk?.btc_eth_max_position_value_ratio || 1,
|
risk?.btc_eth_max_position_value_ratio || 10,
|
||||||
altcoin_max_position_value_ratio:
|
altcoin_max_position_value_ratio:
|
||||||
risk?.altcoin_max_position_value_ratio || 1,
|
risk?.altcoin_max_position_value_ratio || 10,
|
||||||
max_margin_usage: risk?.max_margin_usage || 0.35,
|
max_margin_usage: risk?.max_margin_usage || 1.0,
|
||||||
min_position_size: risk?.min_position_size || 12,
|
min_position_size: risk?.min_position_size || 12,
|
||||||
min_risk_reward_ratio: risk?.min_risk_reward_ratio || 3,
|
min_risk_reward_ratio: risk?.min_risk_reward_ratio || 3,
|
||||||
min_confidence: risk?.min_confidence || 78,
|
min_confidence: risk?.min_confidence || 78,
|
||||||
@@ -1320,9 +1320,9 @@ export function StrategyStudioPage() {
|
|||||||
max_positions: 2,
|
max_positions: 2,
|
||||||
btc_eth_max_leverage: 10,
|
btc_eth_max_leverage: 10,
|
||||||
altcoin_max_leverage: 10,
|
altcoin_max_leverage: 10,
|
||||||
btc_eth_max_position_value_ratio: 1,
|
btc_eth_max_position_value_ratio: 10,
|
||||||
altcoin_max_position_value_ratio: 1,
|
altcoin_max_position_value_ratio: 10,
|
||||||
max_margin_usage: 0.35,
|
max_margin_usage: 1.0,
|
||||||
min_confidence: 78,
|
min_confidence: 78,
|
||||||
min_risk_reward_ratio: 3,
|
min_risk_reward_ratio: 3,
|
||||||
}),
|
}),
|
||||||
@@ -1428,9 +1428,9 @@ export function StrategyStudioPage() {
|
|||||||
max_positions: 2,
|
max_positions: 2,
|
||||||
btc_eth_max_leverage: 10,
|
btc_eth_max_leverage: 10,
|
||||||
altcoin_max_leverage: 10,
|
altcoin_max_leverage: 10,
|
||||||
btc_eth_max_position_value_ratio: 1,
|
btc_eth_max_position_value_ratio: 10,
|
||||||
altcoin_max_position_value_ratio: 1,
|
altcoin_max_position_value_ratio: 10,
|
||||||
max_margin_usage: 0.35,
|
max_margin_usage: 1.0,
|
||||||
min_confidence: 78,
|
min_confidence: 78,
|
||||||
min_risk_reward_ratio: 3,
|
min_risk_reward_ratio: 3,
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user