提前赎回
用户可以在投资周期结束前赎回 AI 交易订单。赎回时,将根据周期已经过的时间比例收取提前赎回罚金。本页介绍罚金公式、赎回 API 和返回结果的结构。
罚金机制
罚金旨在限制过早提取,同时仍然允许用户在需要时退出。提取越早,罚金越高。
Penalty decreases as cycle progresses:
100% ┐
│ ████
75% │ ████████
│ ████████████
50% │ ████████████████
│ ████████████████████
25% │ ████████████████████████
│ ████████████████████████████
0% └────────────────────────────────
0% 25% 50% 75% 100%
Cycle Completion
罚金公式
罚金按毛利润(而非总资金)的百分比计算。如果订单处于亏损状态,不会对亏损部分收取罚金。
completionRate = daysElapsed / cycleDays
penaltyPercent = maxPenaltyPercent * (1 - completionRate)
penaltyAmount = max(0, grossProfit) * penaltyPercent
netPayout = finalNav - penaltyAmount
其中:
| 变量 | 描述 |
|---|---|
completionRate | 周期已经过的比例(0 到 1) |
daysElapsed | 订单激活以来经过的天数 |
cycleDays | 总锁定期天数 |
maxPenaltyPercent | 最大罚金百分比,通常为 30%(0.30) |
grossProfit | finalNav - investedAmount(可以为负数) |
penaltyAmount | 作为罚金扣除的绝对金额 |
netPayout | 返还给用户的金额 |
亏损不收罚金
如果订单处于亏损状态(grossProfit <= 0),则不收取罚金。无论周期完成率如何,用户都将收到完整的 finalNav。罚金仅适用于利润部分。
罚金示例
下表展示了在 30% 最大罚金下,初始投资 $1,000、毛利润 $200(最终 NAV $1,200)在不同完成率下的罚金情况。
| 完成率 | 已过天数(30 天周期) | 罚金 % | 罚金金额 | 净支付 |
|---|---|---|---|---|
| 0%(第 0 天) | 0 | 30% | $60.00 | $1,140.00 |
| 25%(第 7.5 天) | 7.5 | 22.5% | $45.00 | $1,155.00 |
| 50%(第 15 天) | 15 | 15% | $30.00 | $1,170.00 |
| 75%(第 22.5 天) | 22.5 | 7.5% | $15.00 | $1,185.00 |
| 90%(第 27 天) | 27 | 3% | $6.00 | $1,194.00 |
| 100%(第 30 天) | 30 | 0% | $0.00 | $1,200.00 |
如果同一订单处于亏损状态(例如最终 NAV $950,毛利润 -$50):
| 完成率 | 罚金 % | 罚金金额 | 净支付 |
|---|---|---|---|
| 任何 | 0% | $0.00 | $950.00 |
赎回订单
使用 redeemAIOrder 方法执行提前赎回。此方法适用于 active 或 paused 状态的订单。
import { OneEngineClient, setAITradingAccessToken } from '@one_deploy/sdk';
setAITradingAccessToken(userToken);
const engine = new OneEngineClient({
apiKey: process.env.ONE_API_KEY!,
projectId: process.env.ONE_PROJECT_ID!,
});
const result = await engine.redeemAIOrder('order_xyz789');
console.log('Final NAV:', result.finalNav);
console.log('Gross profit:', result.grossProfit);
console.log('Completion rate:', (result.completionRate * 100).toFixed(1) + '%');
console.log('Penalty:', result.penaltyPercent + '%', '=', '$' + result.penaltyAmount.toFixed(2));
console.log('Net payout:', '$' + result.netPayout.toFixed(2));
console.log('Payout tx:', result.transactionHash);
方法签名
redeemAIOrder(orderId: string): Promise<AIRedemptionResult>
AIRedemptionResult 类型
interface AIRedemptionResult {
/** The updated order object with status 'redeemed'. */
order: AIOrder;
/** NAV at the time of redemption. */
finalNav: number;
/** Gross profit before penalty (finalNav - invested amount). */
grossProfit: number;
/** Penalty amount deducted for early withdrawal. 0 if the cycle completed or at a loss. */
penaltyAmount: number;
/** Penalty percentage applied (0-30). */
penaltyPercent: number;
/** Net amount paid out to the user (finalNav - penaltyAmount). */
netPayout: number;
/** Wallet address the payout was sent to. */
payoutAddress: string;
/** On-chain transaction hash for the payout. */
transactionHash: string;
/** Completion rate at the time of redemption (0 to 1). */
completionRate: number;
/** ISO 8601 timestamp of the redemption. */
redeemedAt: string;
}
提前赎回确认界面
在赎回之前,应向用户展示他们将承担的罚金预览。以下是一个确认页面示例。
import { useState, useEffect } from 'react';
import { OneEngineClient, DEFAULT_SHARE_RATES } from '@one_deploy/sdk';
import type { AIOrder, AIRedemptionResult } from '@one_deploy/sdk';
const MAX_PENALTY_PERCENT = 0.30;
interface WithdrawalConfirmProps {
engine: OneEngineClient;
order: AIOrder;
onComplete: (result: AIRedemptionResult) => void;
}
function WithdrawalConfirm({ engine, order, onComplete }: WithdrawalConfirmProps) {
const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState<string | null>(null);
// Calculate estimated penalty
const now = new Date();
const created = new Date(order.createdAt);
const expires = new Date(order.expiresAt);
const totalDays = (expires.getTime() - created.getTime()) / (1000 * 60 * 60 * 24);
const elapsedDays = (now.getTime() - created.getTime()) / (1000 * 60 * 60 * 24);
const completionRate = Math.min(elapsedDays / totalDays, 1);
const grossProfit = order.currentNav - order.amount;
const penaltyPercent = grossProfit > 0
? MAX_PENALTY_PERCENT * (1 - completionRate)
: 0;
const penaltyAmount = Math.max(0, grossProfit) * penaltyPercent;
const estimatedPayout = order.currentNav - penaltyAmount;
const handleRedeem = async () => {
setSubmitting(true);
setError(null);
try {
const result = await engine.redeemAIOrder(order.id);
onComplete(result);
} catch (err) {
setError(err instanceof Error ? err.message : 'Redemption failed');
} finally {
setSubmitting(false);
}
};
return (
<View style={styles.container}>
<Text style={styles.heading}>Early Withdrawal</Text>
<Text style={styles.warning}>
You are redeeming before the cycle ends. A penalty may apply.
</Text>
<View style={styles.details}>
<DetailRow label="Invested" value={`$${order.amount.toFixed(2)}`} />
<DetailRow label="Current NAV" value={`$${order.currentNav.toFixed(2)}`} />
<DetailRow label="Gross Profit" value={`$${grossProfit.toFixed(2)}`} />
<DetailRow
label="Cycle Progress"
value={`${(completionRate * 100).toFixed(1)}% (${elapsedDays.toFixed(0)} / ${totalDays.toFixed(0)} days)`}
/>
<DetailRow
label="Penalty"
value={`${(penaltyPercent * 100).toFixed(1)}% = $${penaltyAmount.toFixed(2)}`}
/>
<View style={styles.divider} />
<DetailRow
label="Estimated Payout"
value={`$${estimatedPayout.toFixed(2)}`}
bold
/>
</View>
{error && <Text style={styles.error}>{error}</Text>}
<Pressable
onPress={handleRedeem}
disabled={submitting}
style={styles.redeemButton}
>
<Text style={styles.redeemButtonText}>
{submitting ? 'Processing...' : 'Confirm Withdrawal'}
</Text>
</Pressable>
<Text style={styles.disclaimer}>
Final amounts are calculated at the time of execution and may differ
slightly from the estimates shown above due to NAV changes.
</Text>
</View>
);
}
function DetailRow({
label,
value,
bold,
}: {
label: string;
value: string;
bold?: boolean;
}) {
return (
<View style={styles.detailRow}>
<Text style={bold ? styles.boldLabel : styles.label}>{label}</Text>
<Text style={bold ? styles.boldValue : styles.value}>{value}</Text>
</View>
);
}
要点总结
- 罚金仅适用于利润,绝不会扣除原始资本。
- 如果订单处于亏损状态,全额返还当前 NAV,不收取罚金。
- 最大罚金为毛利润的 30%,在完成率为 0% 时适用。
- 罚金随周期进展向完成方向线性递减。
- 100% 完成时(周期结束),罚金为 0% -- 订单正常完成。
- 罚金在赎回时刻计算 -- 预览中显示的数值为估算值。