|
|
@@ -61,6 +61,60 @@
|
|
|
<Cell title="可开数量" :value="calculations.sellQty" />
|
|
|
<Cell title="预估手续费" :value="formatDecimal(serivcefee)" />
|
|
|
</CellGroup>
|
|
|
+ <!-- 任务 #7130 -->
|
|
|
+ <div class="order-tpsl" v-if="quote?.tpslflag">
|
|
|
+ <div class="order-tpsl__tp">
|
|
|
+ <div class="left">
|
|
|
+ <Checkbox v-model="formData.TPFlag" :disabled="!!quote.tpslforceflag">{{
|
|
|
+ $t('tss.tpspforceflag') }}
|
|
|
+ </Checkbox>
|
|
|
+ </div>
|
|
|
+ <div class="right">
|
|
|
+ <div class="right-top">
|
|
|
+ <span>{{ $t('tss.stopLossSpread') }}{{ (tpsl.takeProfitSpread > 0 ? '+' : '')
|
|
|
+ + tpsl.takeProfitSpread.toFixed(quote.decimalplace) }}</span>
|
|
|
+ <span class="g-price-up">[{{ takeProfitRatio.toFixed(2) }}%]</span>
|
|
|
+ <span class="g-price-up">+{{ tpsl.takeProfit.toFixed(2) }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="right-bottom">
|
|
|
+ <Button size="small" icon="minus"
|
|
|
+ :disabled="!formData.TPFlag || takeProfitRatio <= profitLossLimits.minProfitRatio" round
|
|
|
+ @click="sliderDecrease()" />
|
|
|
+ <Slider v-model="takeProfitRatio" :bar-height="6" :min="profitLossLimits.minProfitRatio"
|
|
|
+ :max="profitLossLimits.maxProfitRatio" :step="sliderStep"
|
|
|
+ :disabled="!formData.TPFlag" />
|
|
|
+ <Button size="small" icon="plus"
|
|
|
+ :disabled="!formData.TPFlag || takeProfitRatio >= profitLossLimits.maxProfitRatio" round
|
|
|
+ @click="sliderIncrease()" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="order-tpsl__sl">
|
|
|
+ <div class="left">
|
|
|
+ <Checkbox v-model="formData.SLFlag" :disabled="!!quote?.tpslforceflag">{{
|
|
|
+ $t('tss.tpslforceflag') }}
|
|
|
+ </Checkbox>
|
|
|
+ </div>
|
|
|
+ <div class="right">
|
|
|
+ <div class="right-top">
|
|
|
+ <span>{{ $t('tss.stopLossSpread') }}{{ (tpsl.stopLossSpread > 0 ? '+' : '')
|
|
|
+ + tpsl.stopLossSpread.toFixed(quote.decimalplace) }}</span>
|
|
|
+ <span class="g-price-down">[{{ stopLossRatio.toFixed(2) }}%]</span>
|
|
|
+ <span class="g-price-down">{{ tpsl.stopLoss.toFixed(2) }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="right-bottom">
|
|
|
+ <Button size="small" icon="minus"
|
|
|
+ :disabled="!formData.SLFlag || stopLossRatio <= profitLossLimits.minLossRatio" round
|
|
|
+ @click="sliderDecrease('sl')" />
|
|
|
+ <Slider v-model="stopLossRatio" :bar-height="6" :min="profitLossLimits.minLossRatio"
|
|
|
+ :max="profitLossLimits.maxLossRatio" :step="sliderStep" :disabled="!formData.SLFlag" />
|
|
|
+ <Button size="small" icon="plus"
|
|
|
+ :disabled="!formData.SLFlag || stopLossRatio >= profitLossLimits.maxLossRatio" round
|
|
|
+ @click="sliderIncrease('sl')" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</Form>
|
|
|
<Row class="g-layout-block g-layout-block--inset">
|
|
|
<Col span="24">
|
|
|
@@ -83,7 +137,7 @@
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
import { shallowRef, computed, onMounted } from 'vue'
|
|
|
-import { Form, FormInstance, Button, CellGroup, Field, Cell, Tab, Tabs, FieldRule, Col, Row } from 'vant'
|
|
|
+import { Form, FormInstance, Button, CellGroup, Field, Cell, Tab, Tabs, FieldRule, Col, Row, Slider, Checkbox } from 'vant'
|
|
|
import { EPriceMode, EValidType, EOrderOperateType, EBuildType } from '@/constants/client'
|
|
|
import { formatDecimal, parsePercent } from '@/filters'
|
|
|
import { useNavigation } from '@mobile/router/navigation'
|
|
|
@@ -105,10 +159,14 @@ const tabIndex = shallowRef(0)
|
|
|
const formRef = shallowRef<FormInstance>()
|
|
|
const showModal = shallowRef(true)
|
|
|
|
|
|
+const accountStore = useAccountStore()
|
|
|
const userStore = useUserStore()
|
|
|
-const taAccountStore = useAccountStore()
|
|
|
|
|
|
const { formData, formSubmit } = useOrder()
|
|
|
+const takeProfitRatio = shallowRef(0) // 止盈比例
|
|
|
+const stopLossRatio = shallowRef(0) // 止损比例
|
|
|
+const sliderStep = 0.01 // 滑块步长
|
|
|
+
|
|
|
const { getSBYJMyOrders } = useSBYJOrderStore()
|
|
|
const quote = computed(() => futuresStore.getQuoteInfo({ goodsid: goodsId }))
|
|
|
const goods = computed(() => futuresStore.getGoods(goodsId ?? 0 )) ?? {}
|
|
|
@@ -125,6 +183,100 @@ const enumName = computed(() => {
|
|
|
return getGoodsCurrencyItemName(quote.value?.currencyid ?? 0)
|
|
|
})
|
|
|
|
|
|
+// 计算市价
|
|
|
+const marketPrice = computed(() => {
|
|
|
+ const { ask = 0, bid = 0 } = quote.value ?? {}
|
|
|
+ return formData.BuyOrSell === BuyOrSell.Buy ? ask : bid
|
|
|
+})
|
|
|
+
|
|
|
+// 预付款
|
|
|
+const usedMargin = computed(() => {
|
|
|
+ const { avaiableBalance = 0 } = accountStore.currentAccount
|
|
|
+ const { marketmarginalgorithm = 0, marketmarginvalue = 0, agreeunit = 0 } = quote.value ?? {}
|
|
|
+
|
|
|
+ // 结果集合
|
|
|
+ const result = {
|
|
|
+ enableQty: 0,
|
|
|
+ deposit: 0
|
|
|
+ }
|
|
|
+
|
|
|
+ const fixed = agreeunit * marketmarginvalue
|
|
|
+ const ratio = fixed * marketPrice.value
|
|
|
+
|
|
|
+ if (fixed && ratio) {
|
|
|
+ const { OrderQty = 0 } = formData
|
|
|
+ if (marketmarginalgorithm === 1) {
|
|
|
+ const qty = Math.trunc(avaiableBalance / ratio)
|
|
|
+ result.deposit = OrderQty * ratio
|
|
|
+ result.enableQty = qty > 0 ? qty : 0
|
|
|
+ }
|
|
|
+ if (marketmarginalgorithm === 2) {
|
|
|
+ const qty = Math.trunc(avaiableBalance / fixed)
|
|
|
+ result.deposit = OrderQty * fixed
|
|
|
+ result.enableQty = qty > 0 ? qty : 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result
|
|
|
+})
|
|
|
+
|
|
|
+// 计算盈亏
|
|
|
+const calcProfitLoss = (ratio: number, profitLoss: 1 | -1) => usedMargin.value.deposit * (ratio / 100) * profitLoss
|
|
|
+
|
|
|
+// 计算价差
|
|
|
+const calcSpread = (value: number, profitLoss: 1 | -1) => {
|
|
|
+ const { agreeunit = 0, decimalplace = 0 } = quote.value ?? {}
|
|
|
+ const { OrderQty = 0 } = formData
|
|
|
+ const spread = value / (OrderQty * agreeunit)
|
|
|
+ const multiplier = Math.pow(10, decimalplace) // 小数位n次方
|
|
|
+ const roundedSpread = profitLoss === 1 ? Math.ceil(spread * multiplier) : Math.floor(spread * multiplier) // 取整
|
|
|
+ return roundedSpread / multiplier // * (props.orderType === 2 ? 1 : -1)
|
|
|
+}
|
|
|
+
|
|
|
+// 盈亏比限制
|
|
|
+const profitLossLimits = computed(() => {
|
|
|
+ const { tpratioup = 0, tpratiodown = 0, slratioup = 0, slratiodown = 0 } = quote.value ?? {}
|
|
|
+ return {
|
|
|
+ maxProfitRatio: tpratioup * 100,
|
|
|
+ minProfitRatio: tpratiodown * 100,
|
|
|
+ maxLossRatio: slratioup * 100,
|
|
|
+ minLossRatio: slratiodown * 100
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 滑块增加
|
|
|
+const sliderIncrease = (actionName = 'tp') => {
|
|
|
+ if (actionName === 'tp') {
|
|
|
+ takeProfitRatio.value += sliderStep
|
|
|
+ } else {
|
|
|
+ stopLossRatio.value += sliderStep
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// 滑块减少
|
|
|
+const sliderDecrease = (actionName = 'tp') => {
|
|
|
+ if (actionName === 'tp') {
|
|
|
+ takeProfitRatio.value -= sliderStep
|
|
|
+ } else {
|
|
|
+ stopLossRatio.value -= sliderStep
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 止盈止损
|
|
|
+const tpsl = computed(() => {
|
|
|
+ const takeProfit = calcProfitLoss(takeProfitRatio.value, 1) // 盈利
|
|
|
+ const takeProfitSpread = calcSpread(takeProfit, 1) // 止盈价差
|
|
|
+ const stopLoss = calcProfitLoss(stopLossRatio.value, -1) // 亏损
|
|
|
+ const stopLossSpread = calcSpread(stopLoss, -1) // 止损价差
|
|
|
+
|
|
|
+ return {
|
|
|
+ takeProfit,
|
|
|
+ takeProfitSpread,
|
|
|
+ stopLoss,
|
|
|
+ stopLossSpread
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
// const spotAccountStore = useSpotAccountStore()
|
|
|
// const baseAccount = computed(() => spotAccountStore.getAccountItem({ currencyid: quote.value?.goodscurrencyid })) // 基础货币账户
|
|
|
// const quoteAccount = computed(() => spotAccountStore.getAccountItem({ currencyid: quote.value?.currencyid })) // 计价货币账户
|
|
|
@@ -152,7 +304,7 @@ const calculations = computed(() => {
|
|
|
const { last = 0, agreeunit = 0 } = quote.value ?? {}
|
|
|
const { OrderPrice = 0, OrderQty = 0 } = formData
|
|
|
|
|
|
- const { balance = 0.0 } = taAccountStore.currentAccount
|
|
|
+ const { balance = 0.0 } = accountStore.currentAccount
|
|
|
|
|
|
const price = formData.PriceMode === EPriceMode.PRICEMODE_MARKET ? last : OrderPrice
|
|
|
|
|
|
@@ -246,7 +398,7 @@ const onSubmit = () => {
|
|
|
// const margin = `预付定金:${formatDecimal(marginalgorithm === 1 ? totalamount*transferdepositratio : orderQty.value*transferdepositratio)}\n`
|
|
|
// const message = orderPrice + qty + orderamount + margin
|
|
|
|
|
|
- const { marketid = 0, goodsid = 0 } = quote.value ?? {}
|
|
|
+ const { marketid = 0, goodsid = 0, tpslflag = 0 } = quote.value ?? {}
|
|
|
dialog({
|
|
|
message: '确认要提交吗?',
|
|
|
showCancelButton: true,
|
|
|
@@ -260,6 +412,14 @@ const onSubmit = () => {
|
|
|
const param112 = userStore.getSystemParamValue('112')
|
|
|
formData.MarketMaxSub = Number(param112) || 100
|
|
|
|
|
|
+ // 止盈止损
|
|
|
+ if (tpslflag) {
|
|
|
+ formData.TPRatio = formData.TPFlag ? takeProfitRatio.value / 100 : 0
|
|
|
+ formData.SLRatio = formData.SLFlag ? stopLossRatio.value / 100 : 0
|
|
|
+ formData.TPFlag = Number(formData.TPFlag)
|
|
|
+ formData.SLFlag = Number(formData.SLFlag)
|
|
|
+ }
|
|
|
+
|
|
|
fullloading((hideLoading) => {
|
|
|
formSubmit().then(() => {
|
|
|
hideLoading('提交成功。', 'success')
|
|
|
@@ -274,10 +434,19 @@ const onSubmit = () => {
|
|
|
|
|
|
onMounted(() => {
|
|
|
if (quote.value) {
|
|
|
+ const { tpslflag = 0, tpratiodefault = 0, slratiodefault = 0 } = quote.value ?? {}
|
|
|
+
|
|
|
formData.BuyOrSell = BuyOrSell.Buy
|
|
|
formData.PriceMode = EPriceMode.PRICEMODE_MARKET
|
|
|
formData.OrderPrice = formData.BuyOrSell === BuyOrSell.Buy ? quote.value.ask : quote.value.bid
|
|
|
formData.PriceMode = EPriceMode.PRICEMODE_MARKET
|
|
|
+
|
|
|
+ if (tpslflag) {
|
|
|
+ formData.TPFlag = 1
|
|
|
+ formData.SLFlag = 1
|
|
|
+ takeProfitRatio.value = tpratiodefault * 100
|
|
|
+ stopLossRatio.value = slratiodefault * 100
|
|
|
+ }
|
|
|
}
|
|
|
})
|
|
|
</script>
|