mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-06 20:41:14 +08:00
feat: add Bitget futures trading support
- Add BitgetTrader with full trading implementation - Support one-way position mode with proper API parameters - Add Bitget to all exchange switch statements - Update exchange icons (Bybit, OKX, Bitget, Lighter) - Add Bitget to frontend exchange config modal
This commit is contained in:
@@ -47,7 +47,7 @@ const HyperliquidIcon: React.FC<IconProps> = ({
|
||||
</svg>
|
||||
)
|
||||
|
||||
// Bybit SVG 图标组件
|
||||
// Bybit SVG 图标组件 (Official from bybit-web3.github.io)
|
||||
const BybitIcon: React.FC<IconProps> = ({
|
||||
width = 24,
|
||||
height = 24,
|
||||
@@ -56,27 +56,26 @@ const BybitIcon: React.FC<IconProps> = ({
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox="0 0 200 200"
|
||||
viewBox="0 0 88 88"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
d="M50.5 53.3H75.5L100 77.8V122.2L75.5 146.7H50.5V53.3Z"
|
||||
fill="#F7A600"
|
||||
/>
|
||||
<path
|
||||
d="M149.5 53.3H124.5L100 77.8V122.2L124.5 146.7H149.5V53.3Z"
|
||||
fill="#F7A600"
|
||||
/>
|
||||
<path
|
||||
d="M75.5 53.3H124.5V77.8H75.5V53.3Z"
|
||||
fill="#F7A600"
|
||||
/>
|
||||
<path
|
||||
d="M75.5 122.2H124.5V146.7H75.5V122.2Z"
|
||||
fill="#F7A600"
|
||||
/>
|
||||
<path d="M0 18.7C0 8.37227 8.37228 0 18.7 0H69.3C79.6277 0 88 8.37228 88 18.7V69.3C88 79.6277 79.6277 88 69.3 88H18.7C8.37227 88 0 79.6277 0 69.3V18.7Z" fill="#404347"/>
|
||||
<path d="M7.57617 26.8067C6.78516 24.0787 8.4775 21.2531 11.2559 20.663L57.6087 10.8173C59.809 10.35 62.0443 11.4443 63.0247 13.4689L83.8443 56.4657L25.1776 87.5101L7.57617 26.8067Z" fill="url(#bybit_grad)"/>
|
||||
<path d="M8.18242 30.1618C7.35049 27.2838 9.27925 24.3413 12.2502 23.9559L73.6865 15.9881C76.2391 15.6571 78.6111 17.3618 79.1111 19.8867L88.0003 64.7771L24.6892 87.2665L8.18242 30.1618Z" fill="white"/>
|
||||
<path d="M0 34.2222C0 28.8221 4.37766 24.4445 9.77778 24.4445H68.4444C79.2447 24.4445 88 33.1998 88 44V68.4445C88 79.2447 79.2447 88 68.4444 88H19.5556C8.75532 88 0 79.2447 0 68.4445V34.2222Z" fill="black"/>
|
||||
<path d="M58.2201 61.1959V42.8755H61.7937V61.1959H58.2201Z" fill="#F7A600"/>
|
||||
<path d="M17.4395 66.6637H9.77795V48.3434H17.1313C20.7049 48.3434 22.7874 50.3505 22.7874 53.4893C22.7874 55.5215 21.4504 56.8345 20.5257 57.2721C21.6315 57.7869 23.0456 58.9438 23.0456 61.3885C23.0456 64.8108 20.7049 66.6637 17.4395 66.6637ZM16.8481 51.5343H13.3516V55.7548H16.8481C18.3642 55.7548 19.2138 54.9064 19.2138 53.6455C19.2138 52.3826 18.3662 51.5343 16.8481 51.5343ZM17.0793 58.9708H13.3516V63.4728H17.0793C18.6994 63.4728 19.47 62.4432 19.47 61.2092C19.472 59.9733 18.6994 58.9708 17.0793 58.9708Z" fill="white"/>
|
||||
<path d="M32.8925 59.1501V66.6637H29.3439V59.1501L23.8419 48.3434H27.7238L31.1432 55.7278L34.5107 48.3434H38.3926L32.8925 59.1501Z" fill="white"/>
|
||||
<path d="M48.5633 66.6637H40.9017V48.3434H48.2551C51.8287 48.3434 53.9112 50.3505 53.9112 53.4893C53.9112 55.5215 52.5742 56.8345 51.6495 57.2721C52.7553 57.7869 54.1693 58.9438 54.1693 61.3885C54.1674 64.8108 51.8268 66.6637 48.5633 66.6637ZM47.9719 51.5343H44.4753V55.7548H47.9719C49.488 55.7548 50.3376 54.9064 50.3376 53.6455C50.3357 52.3826 49.488 51.5343 47.9719 51.5343ZM48.2031 58.9708H44.4753V63.4728H48.2031C49.8232 63.4728 50.5938 62.4432 50.5938 61.2092C50.5938 59.9734 49.8213 58.9708 48.2031 58.9708Z" fill="white"/>
|
||||
<path d="M73.439 51.5343V66.6637H69.8654V51.5343H65.0839V48.3434H78.2224V51.5343H73.439Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="bybit_grad" x1="7.33308" y1="25.594" x2="84.6381" y2="21.7216" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#FFD748"/>
|
||||
<stop offset="1" stopColor="#F7A600"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
|
||||
@@ -94,11 +93,32 @@ const OKXIcon: React.FC<IconProps> = ({
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<rect width="200" height="200" rx="24" fill="#000"/>
|
||||
<rect x="40" y="40" width="50" height="50" rx="8" fill="#fff"/>
|
||||
<rect x="110" y="40" width="50" height="50" rx="8" fill="#fff"/>
|
||||
<rect x="40" y="110" width="50" height="50" rx="8" fill="#fff"/>
|
||||
<rect x="110" y="110" width="50" height="50" rx="8" fill="#fff"/>
|
||||
<rect width="200" height="200" rx="40" fill="#000"/>
|
||||
<rect x="35" y="35" width="40" height="40" rx="4" fill="#fff"/>
|
||||
<rect x="80" y="80" width="40" height="40" rx="4" fill="#fff"/>
|
||||
<rect x="125" y="35" width="40" height="40" rx="4" fill="#fff"/>
|
||||
<rect x="35" y="125" width="40" height="40" rx="4" fill="#fff"/>
|
||||
<rect x="125" y="125" width="40" height="40" rx="4" fill="#fff"/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
// Bitget SVG 图标组件
|
||||
const BitgetIcon: React.FC<IconProps> = ({
|
||||
width = 24,
|
||||
height = 24,
|
||||
className,
|
||||
}) => (
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox="0 0 200 200"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<rect width="200" height="200" rx="40" fill="#00F0FF"/>
|
||||
<path d="M60 45L100 45C127.614 45 150 67.3858 150 95C150 122.614 127.614 145 100 145L80 145L80 155L60 155L60 45ZM80 65L80 125L100 125C116.569 125 130 111.569 130 95C130 78.4315 116.569 65 100 65L80 65Z" fill="#000"/>
|
||||
<path d="M75 80L75 110L95 110C103.284 110 110 103.284 110 95C110 86.7157 103.284 80 95 80L75 80Z" fill="#00F0FF"/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
@@ -180,6 +200,26 @@ const AsterIcon: React.FC<IconProps> = ({
|
||||
</svg>
|
||||
)
|
||||
|
||||
// Lighter SVG 图标组件
|
||||
const LighterIcon: React.FC<IconProps> = ({
|
||||
width = 24,
|
||||
height = 24,
|
||||
className,
|
||||
}) => (
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox="0 0 200 200"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<rect width="200" height="200" rx="40" fill="#1A1A2E"/>
|
||||
<path d="M70 50L70 130L130 130L130 150L50 150L50 50L70 50Z" fill="#00D9FF"/>
|
||||
<circle cx="115" cy="65" r="20" fill="#00D9FF"/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
// 获取交易所图标的函数
|
||||
export const getExchangeIcon = (
|
||||
exchangeType: string,
|
||||
@@ -192,11 +232,15 @@ export const getExchangeIcon = (
|
||||
? 'bybit'
|
||||
: exchangeType.toLowerCase().includes('okx')
|
||||
? 'okx'
|
||||
: exchangeType.toLowerCase().includes('hyperliquid')
|
||||
? 'hyperliquid'
|
||||
: exchangeType.toLowerCase().includes('aster')
|
||||
? 'aster'
|
||||
: exchangeType.toLowerCase()
|
||||
: exchangeType.toLowerCase().includes('bitget')
|
||||
? 'bitget'
|
||||
: exchangeType.toLowerCase().includes('hyperliquid')
|
||||
? 'hyperliquid'
|
||||
: exchangeType.toLowerCase().includes('aster')
|
||||
? 'aster'
|
||||
: exchangeType.toLowerCase().includes('lighter')
|
||||
? 'lighter'
|
||||
: exchangeType.toLowerCase()
|
||||
|
||||
const iconProps = {
|
||||
width: props.width || 24,
|
||||
@@ -211,11 +255,15 @@ export const getExchangeIcon = (
|
||||
return <BybitIcon {...iconProps} />
|
||||
case 'okx':
|
||||
return <OKXIcon {...iconProps} />
|
||||
case 'bitget':
|
||||
return <BitgetIcon {...iconProps} />
|
||||
case 'hyperliquid':
|
||||
case 'dex':
|
||||
return <HyperliquidIcon {...iconProps} />
|
||||
case 'aster':
|
||||
return <AsterIcon {...iconProps} />
|
||||
case 'lighter':
|
||||
return <LighterIcon {...iconProps} />
|
||||
case 'cex':
|
||||
default:
|
||||
return (
|
||||
|
||||
@@ -21,6 +21,7 @@ const SUPPORTED_EXCHANGE_TEMPLATES = [
|
||||
{ exchange_type: 'binance', name: 'Binance Futures', type: 'cex' as const },
|
||||
{ exchange_type: 'bybit', name: 'Bybit Futures', type: 'cex' as const },
|
||||
{ exchange_type: 'okx', name: 'OKX Futures', type: 'cex' as const },
|
||||
{ exchange_type: 'bitget', name: 'Bitget Futures', type: 'cex' as const },
|
||||
{ exchange_type: 'hyperliquid', name: 'Hyperliquid', type: 'dex' as const },
|
||||
{ exchange_type: 'aster', name: 'Aster DEX', type: 'dex' as const },
|
||||
{ exchange_type: 'lighter', name: 'Lighter', type: 'dex' as const },
|
||||
@@ -123,6 +124,7 @@ export function ExchangeConfigModal({
|
||||
binance: { url: 'https://www.binance.com/join?ref=NOFXENG', hasReferral: true },
|
||||
okx: { url: 'https://www.okx.com/join/1865360', hasReferral: true },
|
||||
bybit: { url: 'https://partner.bybit.com/b/83856', hasReferral: true },
|
||||
bitget: { url: 'https://www.bitget.com/referral/register?from=referral&clacCode=c8a43172', hasReferral: true },
|
||||
hyperliquid: { url: 'https://app.hyperliquid.xyz/join/AITRADING', hasReferral: true },
|
||||
aster: { url: 'https://www.asterdex.com/en/referral/fdfc0e', hasReferral: true },
|
||||
lighter: { url: 'https://lighter.xyz', hasReferral: false },
|
||||
@@ -282,6 +284,9 @@ export function ExchangeConfigModal({
|
||||
} else if (currentExchangeType === 'okx') {
|
||||
if (!apiKey.trim() || !secretKey.trim() || !passphrase.trim()) return
|
||||
await onSave(exchangeId, exchangeType, trimmedAccountName, apiKey.trim(), secretKey.trim(), passphrase.trim(), testnet)
|
||||
} else if (currentExchangeType === 'bitget') {
|
||||
if (!apiKey.trim() || !secretKey.trim() || !passphrase.trim()) return
|
||||
await onSave(exchangeId, exchangeType, trimmedAccountName, apiKey.trim(), secretKey.trim(), passphrase.trim(), testnet)
|
||||
} else if (currentExchangeType === 'hyperliquid') {
|
||||
if (!apiKey.trim() || !hyperliquidWalletAddr.trim()) return // 验证私钥和钱包地址
|
||||
await onSave(
|
||||
@@ -533,10 +538,11 @@ export function ExchangeConfigModal({
|
||||
|
||||
{selectedTemplate && (
|
||||
<>
|
||||
{/* Binance/Bybit/OKX 的输入字段 */}
|
||||
{/* Binance/Bybit/OKX/Bitget 的输入字段 */}
|
||||
{(currentExchangeType === 'binance' ||
|
||||
currentExchangeType === 'bybit' ||
|
||||
currentExchangeType === 'okx') && (
|
||||
currentExchangeType === 'okx' ||
|
||||
currentExchangeType === 'bitget') && (
|
||||
<>
|
||||
{/* 币安用户配置提示 (D1 方案) */}
|
||||
{currentExchangeType === 'binance' && (
|
||||
@@ -681,7 +687,7 @@ export function ExchangeConfigModal({
|
||||
/>
|
||||
</div>
|
||||
|
||||
{currentExchangeType === 'okx' && (
|
||||
{(currentExchangeType === 'okx' || currentExchangeType === 'bitget') && (
|
||||
<div>
|
||||
<label
|
||||
className="block text-sm font-semibold mb-2"
|
||||
@@ -1184,6 +1190,10 @@ export function ExchangeConfigModal({
|
||||
(!apiKey.trim() ||
|
||||
!secretKey.trim() ||
|
||||
!passphrase.trim())) ||
|
||||
(currentExchangeType === 'bitget' &&
|
||||
(!apiKey.trim() ||
|
||||
!secretKey.trim() ||
|
||||
!passphrase.trim())) ||
|
||||
(currentExchangeType === 'hyperliquid' &&
|
||||
(!apiKey.trim() || !hyperliquidWalletAddr.trim())) || // 验证私钥和钱包地址
|
||||
(currentExchangeType === 'aster' &&
|
||||
@@ -1201,6 +1211,7 @@ export function ExchangeConfigModal({
|
||||
currentExchangeType !== 'binance' &&
|
||||
currentExchangeType !== 'bybit' &&
|
||||
currentExchangeType !== 'okx' &&
|
||||
currentExchangeType !== 'bitget' &&
|
||||
(!apiKey.trim() || !secretKey.trim()))
|
||||
}
|
||||
className="flex-1 px-4 py-2 rounded text-sm font-semibold disabled:opacity-50"
|
||||
|
||||
Reference in New Issue
Block a user