diff --git a/src/api/market.ts b/src/api/market.ts
index 975381b..176122d 100644
--- a/src/api/market.ts
+++ b/src/api/market.ts
@@ -15,7 +15,7 @@ export interface ClobSubmitOrderRequest {
/** 价格(整数,已乘 10000) */
price: number
side: number
- /** 数量(份额) */
+ /** 数量(micro units,1_000_000 = 1 share,支持 6 位小数份额) */
size: number
taker: boolean
tokenID: string
diff --git a/src/components/TradeComponent.vue b/src/components/TradeComponent.vue
index fef811e..4343ab1 100644
--- a/src/components/TradeComponent.vue
+++ b/src/components/TradeComponent.vue
@@ -97,14 +97,15 @@
- {{ t('trade.sharesExceedsMax', { max: maxAvailableShares }) }}
+ {{ t('trade.sharesExceedsMax', { max: maxAvailableSharesDisplay }) }}
mdi-information
@@ -548,14 +551,15 @@
{{ t('trade.shares') }}
{{ t('trade.maxShares') }}: {{ maxAvailableShares }}{{ t('trade.maxShares') }}: {{ maxAvailableSharesDisplay }}
{{ t('trade.shares') }}
{{ t('trade.maxShares') }}: {{ maxAvailableShares }}{{ t('trade.maxShares') }}: {{ maxAvailableSharesDisplay }}
{{ t('trade.shares') }}
{{ t('trade.maxShares') }}: {{ maxAvailableShares }}{{ t('trade.maxShares') }}: {{ maxAvailableSharesDisplay }}
{{ t('trade.shares') }}
{{ t('trade.maxShares') }}: {{ maxAvailableShares }}{{ t('trade.maxShares') }}: {{ maxAvailableSharesDisplay }}
{{ t('trade.shares') }}
{{ t('trade.maxShares') }}: {{ maxAvailableShares }}{{ t('trade.maxShares') }}: {{ maxAvailableSharesDisplay }}
(prefs.limitType)
const expirationEnabled = ref(false)
const selectedOption = ref<'yes' | 'no'>(props.initialOption ?? 'no')
const limitPrice = ref(0.82) // 内部存储 0–1,显示为美分与按钮一致
-const shares = ref(20) // 初始份额(正整数)
+const shares = ref(20) // 初始份额(Buy 为正整数,Sell 支持 6 位小数)
+const ORDER_SIZE_SCALE = 1_000_000
+const ORDER_SIZE_MIN = 1 / ORDER_SIZE_SCALE
const expirationTime = ref('5m') // 初始过期时间
const EXPIRATION_VALUES = [
'5m',
@@ -1836,21 +1847,44 @@ const currentOptionPositionShares = computed(() => {
return totalShares
})
-/** 最大可卖出份额 */
+/** 最大可卖出份额(保留 6 位小数) */
const maxAvailableShares = computed(() => {
- return Math.floor(currentOptionPositionShares.value)
+ return clampSellShares(currentOptionPositionShares.value)
})
-/** 将 shares 限制为正整数(>= 1) */
+/** 展示用最大可卖份额 */
+const maxAvailableSharesDisplay = computed(() =>
+ trimTrailingZeros(maxAvailableShares.value.toFixed(6)),
+)
+
+const sharesInputMin = computed(() => (activeTab.value === 'sell' ? ORDER_SIZE_MIN : 1))
+const sharesInputStep = computed(() => (activeTab.value === 'sell' ? ORDER_SIZE_MIN : 1))
+
+/** 将 shares 限制为正整数(>= 1),Buy 模式使用 */
function clampShares(v: number): number {
const n = Math.floor(Number.isFinite(v) ? v : 1)
return Math.max(1, n)
}
-// 设置最大份额(基于当前选项的持仓);Sell 模式下份额默认取最大可卖数量
+/** Sell 模式:保留 6 位小数 */
+function clampSellShares(v: number): number {
+ if (!Number.isFinite(v) || v <= 0) return 0
+ const scaled = Math.round(v * ORDER_SIZE_SCALE) / ORDER_SIZE_SCALE
+ return scaled < ORDER_SIZE_MIN ? 0 : scaled
+}
+
+function sharesToMicro(v: number): number {
+ return Math.round(v * ORDER_SIZE_SCALE)
+}
+
+// 设置最大份额(基于当前选项的持仓)
const setMaxShares = () => {
const maxShares = currentOptionPositionShares.value
- shares.value = maxShares > 0 ? clampShares(maxShares) : 0
+ if (activeTab.value === 'sell') {
+ shares.value = maxShares > 0 ? clampSellShares(maxShares) : 0
+ } else {
+ shares.value = maxShares > 0 ? clampShares(maxShares) : 0
+ }
}
function applyInitialOption(option: 'yes' | 'no') {
@@ -1995,15 +2029,23 @@ const increasePrice = () => {
limitPrice.value = ALLOWED_LIMIT_PRICES[nextIdx] ?? limitPrice.value
}
-/** 仅在值为正整数时更新 shares */
+/** 更新 shares:Buy 仅正整数,Sell 支持 6 位小数 */
function onSharesInput(v: unknown) {
const num = v == null ? NaN : Number(v)
+ if (!Number.isFinite(num)) return
+ if (activeTab.value === 'sell') {
+ if (num <= 0) return
+ const scaled = clampSellShares(num)
+ if (scaled <= 0) return
+ shares.value = scaled
+ return
+ }
const n = Math.floor(num)
- if (!Number.isFinite(num) || n < 1 || num !== n) return
+ if (n < 1 || num !== n) return
shares.value = n
}
-/** 只允许数字输入(Shares 为正整数) */
+/** 键盘输入:Sell 允许小数点 */
function onSharesKeydown(e: KeyboardEvent) {
const key = e.key
const allowed = ['Backspace', 'Delete', 'Tab', 'ArrowLeft', 'ArrowRight', 'Home', 'End']
@@ -2012,12 +2054,24 @@ function onSharesKeydown(e: KeyboardEvent) {
if (['a', 'c', 'v', 'x'].includes(key.toLowerCase())) return
}
if (key >= '0' && key <= '9') return
+ if (
+ activeTab.value === 'sell' &&
+ key === '.' &&
+ !String((e.target as HTMLInputElement)?.value ?? '').includes('.')
+ ) {
+ return
+ }
e.preventDefault()
}
-/** 粘贴时只接受正整数 */
+/** 粘贴:Sell 接受小数,Buy 仅正整数 */
function onSharesPaste(e: ClipboardEvent) {
const text = e.clipboardData?.getData('text') ?? ''
+ if (activeTab.value === 'sell') {
+ const num = parseFloat(text)
+ if (!Number.isFinite(num) || num <= 0) e.preventDefault()
+ return
+ }
const num = parseInt(text, 10)
if (!Number.isFinite(num) || num < 1) e.preventDefault()
}
@@ -2031,14 +2085,15 @@ const adjustShares = (amount: number) => {
const sellSharesExceedsMax = computed(
() =>
activeTab.value === 'sell' &&
- maxAvailableShares.value >= 0 &&
- shares.value > maxAvailableShares.value,
+ maxAvailableShares.value > 0 &&
+ sharesToMicro(shares.value) > sharesToMicro(maxAvailableShares.value),
)
// 份额百分比调整方法(仅在Sell模式下使用)
const setSharesPercentage = (percentage: number) => {
- const maxShares = currentOptionPositionShares.value || 100
- shares.value = clampShares(Math.round((maxShares * percentage) / 100))
+ const maxShares = currentOptionPositionShares.value
+ if (!Number.isFinite(maxShares) || maxShares <= 0) return
+ shares.value = clampSellShares((maxShares * percentage) / 100)
}
// Market mode methods
@@ -2160,8 +2215,8 @@ async function submitOrder() {
isNoAvailableSharesError.value = true
return
}
- if (shares.value > maxShares) {
- orderError.value = t('trade.sharesExceedsMax', { max: maxShares })
+ if (sharesToMicro(shares.value) > sharesToMicro(maxShares)) {
+ orderError.value = t('trade.sharesExceedsMax', { max: maxAvailableSharesDisplay.value })
isNoAvailableSharesError.value = false
return
}
@@ -2179,8 +2234,23 @@ async function submitOrder() {
? parseExpirationTimestamp(expirationTime.value)
: 0
- const rawSize = isMarket && activeTab.value === 'buy' ? amount.value : clampShares(shares.value)
- const sizeValue = Math.round(rawSize * 1_000_000)
+ const rawSize =
+ isMarket && activeTab.value === 'buy'
+ ? amount.value
+ : activeTab.value === 'sell'
+ ? clampSellShares(shares.value)
+ : clampShares(shares.value)
+ if (activeTab.value === 'sell' && rawSize <= 0) {
+ orderError.value = t('trade.orderFailed')
+ isNoAvailableSharesError.value = false
+ return
+ }
+ const sizeValue = sharesToMicro(rawSize)
+ if (sizeValue <= 0) {
+ orderError.value = t('trade.orderFailed')
+ isNoAvailableSharesError.value = false
+ return
+ }
orderLoading.value = true
orderError.value = ''