add bybit trading stop

master
TZGyn 6 months ago
parent dc4cd0a5c8
commit d3447351e4
Signed by: TZGyn
GPG Key ID: 122EAF77AE81FD4A

@ -42,6 +42,12 @@
icon: CoinsIcon,
isActive: page.url.pathname === `/dashboard/bybit`,
},
{
title: 'ByBit Trading Stop',
url: `/dashboard/trading-stop`,
icon: CoinsIcon,
isActive: page.url.pathname === `/dashboard/trading-stop`,
},
{
title: 'Logs',
url: `/dashboard/logs`,

@ -0,0 +1,189 @@
<script lang="ts">
import * as Tabs from '$lib/components/ui/tabs/index.js'
import * as Form from '$lib/components/ui/form'
import * as Select from '$lib/components/ui/select'
import { Input } from '$lib/components/ui/input'
import { superForm } from 'sveltekit-superforms'
import { zod } from 'sveltekit-superforms/adapters'
import { formSchema } from './schema'
import { Slider } from '$lib/components/ui/slider/index.js'
import { JsonView } from '@zerodevx/svelte-json-view'
import copy from 'copy-to-clipboard'
import json5 from 'json5'
import { toast } from 'svelte-sonner'
import { Checkbox } from '$lib/components/ui/checkbox'
let { data } = $props()
const form = superForm(data.form, {
resetForm: false,
SPA: true,
validators: zod(formSchema),
onSubmit: ({}) => {
copy(
json5.stringify(
{
...$formData,
entryPrice: '{trigger_entry_value}',
qtyPercent: $formData.qtyPercent.toString(),
qtyDecimalPoint: $formData.qtyDecimalPoint.toString(),
leverage: $formData.leverage.toString(),
takeProfitPercent: $formData.takeProfitPercent.toString(),
stopLossPercent: $formData.stopLossPercent.toString(),
demo: $formData.demo.toString(),
},
null,
2,
),
)
toast.success('Copied to Clipboard')
},
})
const { form: formData, enhance } = form
</script>
<div class="flex flex-1 flex-col items-center justify-center">
<div>
<form method="POST" use:enhance class="grid grid-cols-2 gap-4">
<Form.Field {form} name="key">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Key</Form.Label>
<Input {...props} bind:value={$formData.key} />
{/snippet}
</Form.Control>
<Form.Description>Key</Form.Description>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="secret">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Secret</Form.Label>
<Input {...props} bind:value={$formData.secret} />
{/snippet}
</Form.Control>
<Form.Description>Secret</Form.Description>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="symbol">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Symbol</Form.Label>
<Input {...props} bind:value={$formData.symbol} />
{/snippet}
</Form.Control>
<Form.Description>Symbol</Form.Description>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="qtyPercent">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Quantity (%)</Form.Label>
<Input
type="number"
{...props}
step={0.1}
bind:value={$formData.qtyPercent} />
{/snippet}
</Form.Control>
<Form.Description>Quantity</Form.Description>
<Form.FieldErrors />
<Slider
type="single"
bind:value={$formData.qtyPercent}
max={100}
step={0.1} />
</Form.Field>
<Form.Field {form} name="qtyDecimalPoint">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Quantity Decimal Point</Form.Label>
<Input
type="number"
{...props}
step={1}
bind:value={$formData.qtyDecimalPoint} />
{/snippet}
</Form.Control>
<Form.Description>Quantity</Form.Description>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="leverage">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Leverage</Form.Label>
<Input
type="number"
{...props}
bind:value={$formData.leverage} />
{/snippet}
</Form.Control>
<Form.Description>Leverage</Form.Description>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="takeProfitPercent">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Take Profit (%)</Form.Label>
<Input
type="number"
{...props}
step={0.1}
bind:value={$formData.takeProfitPercent} />
{/snippet}
</Form.Control>
<Form.Description>Take Profit</Form.Description>
<Form.FieldErrors />
<Slider
type="single"
bind:value={$formData.takeProfitPercent}
max={100}
step={0.1} />
</Form.Field>
<Form.Field {form} name="stopLossPercent">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Stop Loss (%)</Form.Label>
<Input
type="number"
{...props}
step={0.1}
bind:value={$formData.stopLossPercent} />
{/snippet}
</Form.Control>
<Form.Description>Stop Loss</Form.Description>
<Form.FieldErrors />
<Slider
type="single"
bind:value={$formData.stopLossPercent}
max={100}
step={0.1} />
</Form.Field>
<Form.Field {form} name="demo">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Demo</Form.Label>
<Checkbox {...props} bind:checked={$formData.demo} />
{/snippet}
</Form.Control>
<Form.Description>Demo</Form.Description>
<Form.FieldErrors />
</Form.Field>
<Form.Button class="col-span-2">Copy</Form.Button>
</form>
<JsonView
json={{
...$formData,
entryPrice: '{trigger_entry_value}',
qtyPercent: $formData.qtyPercent.toString(),
qtyDecimalPoint: $formData.qtyDecimalPoint.toString(),
leverage: $formData.leverage.toString(),
takeProfitPercent: $formData.takeProfitPercent.toString(),
stopLossPercent: $formData.stopLossPercent.toString(),
demo: $formData.demo.toString(),
}} />
</div>
</div>

@ -0,0 +1,17 @@
import { superValidate } from 'sveltekit-superforms'
import { zod } from 'sveltekit-superforms/adapters'
import { formSchema } from './schema'
export const load = async () => {
const form = await superValidate(
{
key: '',
secret: '',
symbol: 'BTCUSDT',
},
zod(formSchema),
{ errors: false },
)
return { form }
}

@ -0,0 +1,15 @@
import { z } from 'zod'
export const formSchema = z.object({
key: z.string(),
secret: z.string(),
symbol: z.string(),
qtyPercent: z.number(),
qtyDecimalPoint: z.number(),
leverage: z.number().default(1),
takeProfitPercent: z.number(),
stopLossPercent: z.number(),
demo: z.boolean().default(true),
})
export type FormSchema = typeof formSchema

@ -0,0 +1,178 @@
import { db } from '$lib/db/index.js'
import { bybit_logs } from '$lib/db/schema.js'
import { json } from '@sveltejs/kit'
import { RestClientV5 } from 'bybit-api'
import { z } from 'zod'
export const POST = async ({ locals, request }) => {
const type = request.headers.get('Content-Type')
console.log(type)
if (!type || !type.startsWith('application/json')) {
return new Response()
}
const body = await request.json()
console.log('Body:', body)
const schema = z.object({
key: z.string(),
secret: z.string(),
symbol: z.string(),
entryPrice: z.string(),
qtyPercent: z.string(),
qtyDecimalPoint: z.string(),
leverage: z.string().default('1'),
takeProfitPercent: z.string(),
stopLossPercent: z.string(),
demo: z.enum(['true', 'false']),
})
const form = schema.safeParse(body)
if (!form.success) {
console.log(form.error)
return json({}, { status: 400 })
}
const { key, secret, symbol, demo } = form.data
try {
const client = new RestClientV5({
key: key,
secret: secret,
demoTrading: demo === 'true',
})
client.switchPositionMode({
category: 'linear',
mode: 3,
})
const wallet = await client.getWalletBalance({
accountType: 'UNIFIED',
coin: 'USDT',
})
console.log(
'Available Balance:',
wallet.result.list[0].totalAvailableBalance,
)
console.log('calculate:')
console.log('Entry Price:', form.data.entryPrice)
console.log('Qty Percent:', form.data.qtyPercent)
console.log(
'Wallet Balance:',
wallet.result.list[0].totalAvailableBalance,
)
const [price, decimals] = form.data.entryPrice.split('.')
console.log('Decimals', decimals)
console.log('Decimals Length', decimals?.length || 0)
const decimalLength = decimals?.length || 0
const qty = (
(Number(wallet.result.list[0].totalAvailableBalance) *
((Number(form.data.qtyPercent) / 100) *
Number(form.data.leverage || '1'))) /
Number(form.data.entryPrice)
).toFixed(Number(form.data.qtyDecimalPoint))
const takeProfitBuy = (
Number(form.data.entryPrice) *
(1 + Number(form.data.takeProfitPercent) / 100)
).toFixed(decimalLength)
const stopLossBuy = (
Number(form.data.entryPrice) *
(1 - Number(form.data.stopLossPercent) / 100)
).toFixed(decimalLength)
const takeProfitSell = (
Number(form.data.entryPrice) *
(1 - Number(form.data.takeProfitPercent) / 100)
).toFixed(decimalLength)
const stopLossSell = (
Number(form.data.entryPrice) *
(1 + Number(form.data.stopLossPercent) / 100)
).toFixed(decimalLength)
console.log({
qty,
takeProfitBuy,
stopLossBuy,
takeProfitSell,
stopLossSell,
})
const orders = await Promise.all([
await client.submitOrder({
category: 'linear',
symbol,
side: 'Buy',
orderType: 'Market',
qty,
takeProfit: takeProfitBuy,
stopLoss: stopLossBuy,
isLeverage: form.data.leverage ? 1 : 0,
positionIdx: 1,
}),
await client.submitOrder({
category: 'linear',
symbol,
side: 'Sell',
orderType: 'Market',
qty,
takeProfit: takeProfitSell,
stopLoss: stopLossSell,
isLeverage: form.data.leverage ? 1 : 0,
positionIdx: 2,
}),
])
console.log('Orders:', orders)
const buyOrder = orders[0]
await db.insert(bybit_logs).values({
status: buyOrder.retCode === 0 ? 'success' : 'failed',
request: form.data,
payload: {
category: 'linear',
symbol,
side: 'Buy',
orderType: 'Market',
qty,
takeProfit: takeProfitBuy,
stopLoss: stopLossBuy,
isLeverage: form.data.leverage ? 1 : 0,
positionIdx: 1,
},
response: buyOrder,
createdAt: Date.now(),
})
const sellOrder = orders[1]
await db.insert(bybit_logs).values({
status: sellOrder.retCode === 0 ? 'success' : 'failed',
request: form.data,
payload: {
category: 'linear',
symbol,
side: 'Sell',
orderType: 'Market',
qty,
takeProfit: takeProfitSell,
stopLoss: stopLossSell,
isLeverage: form.data.leverage ? 1 : 0,
positionIdx: 1,
},
response: sellOrder,
createdAt: Date.now(),
})
return new Response()
} catch (error) {
console.log('Error', error)
} finally {
return new Response()
}
}
Loading…
Cancel
Save