You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
506 lines
14 KiB
Svelte
506 lines
14 KiB
Svelte
<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 {
|
|
closePositionSchema,
|
|
formSchema,
|
|
percentSchema,
|
|
} 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(
|
|
{
|
|
type: 'Flat',
|
|
...$formData,
|
|
qty: $formData.qty.toString(),
|
|
leverage: $formData.leverage.toString(),
|
|
takeProfit: $formData.takeProfit.toString(),
|
|
stopLoss: $formData.stopLoss.toString(),
|
|
hedge: $formData.hedge.toString(),
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
)
|
|
toast.success('Copied to Clipboard')
|
|
},
|
|
})
|
|
|
|
const { form: formData, enhance } = form
|
|
|
|
const percentForm = superForm(data.percentForm, {
|
|
resetForm: false,
|
|
SPA: true,
|
|
validators: zod(percentSchema),
|
|
onSubmit: ({}) => {
|
|
copy(
|
|
JSON.stringify(
|
|
{
|
|
type: 'Percent',
|
|
...$percentFormData,
|
|
entryPrice: '{trigger_entry_value}',
|
|
qtyPercent: $percentFormData.qtyPercent.toString(),
|
|
qtyDecimalPoint:
|
|
$percentFormData.qtyDecimalPoint.toString(),
|
|
leverage: $percentFormData.leverage.toString(),
|
|
takeProfitPercent:
|
|
$percentFormData.takeProfitPercent.toString(),
|
|
stopLossPercent:
|
|
$percentFormData.stopLossPercent.toString(),
|
|
hedge: $percentFormData.hedge.toString(),
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
)
|
|
toast.success('Copied to Clipboard')
|
|
},
|
|
})
|
|
|
|
const { form: percentFormData, enhance: percentEnhance } =
|
|
percentForm
|
|
|
|
const closePositionForm = superForm(data.closePositionForm, {
|
|
resetForm: false,
|
|
SPA: true,
|
|
validators: zod(closePositionSchema),
|
|
onSubmit: ({}) => {
|
|
copy(
|
|
JSON.stringify(
|
|
{
|
|
type: 'Close Position',
|
|
...$closePositionFormData,
|
|
hedge: $closePositionFormData.hedge.toString(),
|
|
side: $closePositionFormData.side.toString(),
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
)
|
|
toast.success('Copied to Clipboard')
|
|
},
|
|
})
|
|
|
|
const {
|
|
form: closePositionFormData,
|
|
enhance: closePositionEnhance,
|
|
} = closePositionForm
|
|
</script>
|
|
|
|
<div class="flex flex-1 flex-col items-center justify-center">
|
|
<Tabs.Root value="percent" class="w-[400px]">
|
|
<Tabs.List class="grid w-full grid-cols-3">
|
|
<Tabs.Trigger value="flat">Flat</Tabs.Trigger>
|
|
<Tabs.Trigger value="percent">Percent</Tabs.Trigger>
|
|
<Tabs.Trigger value="close">Close</Tabs.Trigger>
|
|
</Tabs.List>
|
|
<Tabs.Content value="flat">
|
|
<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="side">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Side</Form.Label>
|
|
<Select.Root
|
|
type="single"
|
|
bind:value={$formData.side}
|
|
name={props.name}>
|
|
<Select.Trigger {...props}>
|
|
{$formData.side ?? 'Select a side'}
|
|
</Select.Trigger>
|
|
<Select.Content>
|
|
<Select.Item value={'Buy'} label={'Buy'} />
|
|
<Select.Item value={'Sell'} label={'Sell'} />
|
|
</Select.Content>
|
|
</Select.Root>
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Side</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field {form} name="qty">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Quantity</Form.Label>
|
|
<Input
|
|
type="number"
|
|
{...props}
|
|
bind:value={$formData.qty} />
|
|
{/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="takeProfit">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Take Profit</Form.Label>
|
|
<Input
|
|
type="number"
|
|
{...props}
|
|
bind:value={$formData.takeProfit} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Take Profit</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field {form} name="stopLoss">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Stop Loss</Form.Label>
|
|
<Input
|
|
type="number"
|
|
{...props}
|
|
bind:value={$formData.stopLoss} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Stop Loss</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field {form} name="hedge">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Hedge</Form.Label>
|
|
<Checkbox {...props} bind:checked={$formData.hedge} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Leverage</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
|
|
<Form.Button class="col-span-2">Copy</Form.Button>
|
|
</form>
|
|
<JsonView
|
|
json={{
|
|
type: 'Flat',
|
|
...$formData,
|
|
qty: $formData.qty.toString(),
|
|
leverage: $formData.leverage.toString(),
|
|
takeProfit: $formData.takeProfit.toString(),
|
|
stopLoss: $formData.stopLoss.toString(),
|
|
hedge: $formData.hedge.toString(),
|
|
}} />
|
|
</Tabs.Content>
|
|
<Tabs.Content value="percent">
|
|
<form
|
|
method="POST"
|
|
use:percentEnhance
|
|
class="grid grid-cols-2 gap-4">
|
|
<Form.Field form={percentForm} name="key">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Key</Form.Label>
|
|
<Input {...props} bind:value={$percentFormData.key} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Key</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field form={percentForm} name="secret">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Secret</Form.Label>
|
|
<Input
|
|
{...props}
|
|
bind:value={$percentFormData.secret} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Secret</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field form={percentForm} name="symbol">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Symbol</Form.Label>
|
|
<Input
|
|
{...props}
|
|
bind:value={$percentFormData.symbol} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Symbol</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field form={percentForm} name="side">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Side</Form.Label>
|
|
<Select.Root
|
|
type="single"
|
|
bind:value={$percentFormData.side}
|
|
name={props.name}>
|
|
<Select.Trigger {...props}>
|
|
{$percentFormData.side ?? 'Select a side'}
|
|
</Select.Trigger>
|
|
<Select.Content>
|
|
<Select.Item value={'Buy'} label={'Buy'} />
|
|
<Select.Item value={'Sell'} label={'Sell'} />
|
|
</Select.Content>
|
|
</Select.Root>
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Side</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field form={percentForm} name="qtyPercent">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Quantity (%)</Form.Label>
|
|
<Input
|
|
type="number"
|
|
{...props}
|
|
step={0.1}
|
|
bind:value={$percentFormData.qtyPercent} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Quantity</Form.Description>
|
|
<Form.FieldErrors />
|
|
<Slider
|
|
type="single"
|
|
bind:value={$percentFormData.qtyPercent}
|
|
max={100}
|
|
step={0.1} />
|
|
</Form.Field>
|
|
<Form.Field form={percentForm} name="qtyDecimalPoint">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Quantity Decimal Point</Form.Label>
|
|
<Input
|
|
type="number"
|
|
{...props}
|
|
step={1}
|
|
bind:value={$percentFormData.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={$percentFormData.leverage} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Leverage</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field form={percentForm} name="takeProfitPercent">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Take Profit (%)</Form.Label>
|
|
<Input
|
|
type="number"
|
|
{...props}
|
|
step={0.1}
|
|
bind:value={$percentFormData.takeProfitPercent} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Take Profit</Form.Description>
|
|
<Form.FieldErrors />
|
|
<Slider
|
|
type="single"
|
|
bind:value={$percentFormData.takeProfitPercent}
|
|
max={100}
|
|
step={0.1} />
|
|
</Form.Field>
|
|
<Form.Field form={percentForm} name="stopLossPercent">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Stop Loss (%)</Form.Label>
|
|
<Input
|
|
type="number"
|
|
{...props}
|
|
step={0.1}
|
|
bind:value={$percentFormData.stopLossPercent} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Stop Loss</Form.Description>
|
|
<Form.FieldErrors />
|
|
<Slider
|
|
type="single"
|
|
bind:value={$percentFormData.stopLossPercent}
|
|
max={100}
|
|
step={0.1} />
|
|
</Form.Field>
|
|
<Form.Field form={percentForm} name="hedge">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Hedge</Form.Label>
|
|
<Checkbox
|
|
{...props}
|
|
bind:checked={$percentFormData.hedge} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Leverage</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
|
|
<Form.Button class="col-span-2">Copy</Form.Button>
|
|
</form>
|
|
<JsonView
|
|
json={{
|
|
type: 'Percent',
|
|
...$percentFormData,
|
|
entryPrice: '{trigger_entry_value}',
|
|
qtyPercent: $percentFormData.qtyPercent.toString(),
|
|
qtyDecimalPoint:
|
|
$percentFormData.qtyDecimalPoint.toString(),
|
|
leverage: $percentFormData.leverage.toString(),
|
|
takeProfitPercent:
|
|
$percentFormData.takeProfitPercent.toString(),
|
|
stopLossPercent:
|
|
$percentFormData.stopLossPercent.toString(),
|
|
hedge: $percentFormData.hedge.toString(),
|
|
}} />
|
|
</Tabs.Content>
|
|
<Tabs.Content value="close">
|
|
<form
|
|
method="POST"
|
|
use:closePositionEnhance
|
|
class="grid grid-cols-2 gap-4">
|
|
<Form.Field form={closePositionForm} name="key">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Key</Form.Label>
|
|
<Input
|
|
{...props}
|
|
bind:value={$closePositionFormData.key} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Key</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field form={closePositionForm} name="secret">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Secret</Form.Label>
|
|
<Input
|
|
{...props}
|
|
bind:value={$closePositionFormData.secret} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Secret</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field form={closePositionForm} name="symbol">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Symbol</Form.Label>
|
|
<Input
|
|
{...props}
|
|
bind:value={$closePositionFormData.symbol} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Symbol</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field form={closePositionForm} name="hedge">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Hedge</Form.Label>
|
|
<Checkbox
|
|
{...props}
|
|
bind:checked={$closePositionFormData.hedge} />
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Leverage</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
{#if $closePositionFormData.hedge}
|
|
<Form.Field form={closePositionForm} name="side">
|
|
<Form.Control>
|
|
{#snippet children({ props })}
|
|
<Form.Label>Side</Form.Label>
|
|
<Select.Root
|
|
type="single"
|
|
bind:value={$closePositionFormData.side}
|
|
name={props.name}>
|
|
<Select.Trigger {...props}>
|
|
{$closePositionFormData.side ?? 'Select a side'}
|
|
</Select.Trigger>
|
|
<Select.Content>
|
|
<Select.Item value={'Buy'} label={'Buy'} />
|
|
<Select.Item value={'Sell'} label={'Sell'} />
|
|
</Select.Content>
|
|
</Select.Root>
|
|
{/snippet}
|
|
</Form.Control>
|
|
<Form.Description>Side</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
{/if}
|
|
<Form.Button class="col-span-2">Copy</Form.Button>
|
|
</form>
|
|
<JsonView
|
|
json={{
|
|
type: 'Close Position',
|
|
...$closePositionFormData,
|
|
hedge: $closePositionFormData.hedge.toString(),
|
|
side: $closePositionFormData.side.toString(),
|
|
}} />
|
|
</Tabs.Content>
|
|
</Tabs.Root>
|
|
</div>
|