mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-10 22:36:58 +08:00
fix: initial balance calculation and UI improvements
- Fix initial balance using available_balance instead of total_equity - Fix WSMonitor nil pointer by starting market monitor before loading traders - Add strategy name display on traders list and dashboard pages - Various position sync and trading improvements
This commit is contained in:
@@ -211,10 +211,10 @@ export function CoinSourceEditor({
|
||||
</span>
|
||||
<input
|
||||
type="number"
|
||||
value={config.coin_pool_limit || 30}
|
||||
value={config.coin_pool_limit || 10}
|
||||
onChange={(e) =>
|
||||
!disabled &&
|
||||
onChange({ ...config, coin_pool_limit: parseInt(e.target.value) || 30 })
|
||||
onChange({ ...config, coin_pool_limit: parseInt(e.target.value) || 10 })
|
||||
}
|
||||
disabled={disabled}
|
||||
min={1}
|
||||
|
||||
@@ -19,15 +19,24 @@ export function RiskControlEditor({
|
||||
positionLimits: { zh: '仓位限制', en: 'Position Limits' },
|
||||
maxPositions: { zh: '最大持仓数量', en: 'Max Positions' },
|
||||
maxPositionsDesc: { zh: '同时持有的最大币种数量', en: 'Maximum coins held simultaneously' },
|
||||
btcEthLeverage: { zh: 'BTC/ETH 最大杠杆', en: 'BTC/ETH Max Leverage' },
|
||||
altcoinLeverage: { zh: '山寨币最大杠杆', en: 'Altcoin Max Leverage' },
|
||||
// Trading leverage (exchange leverage)
|
||||
tradingLeverage: { zh: '交易杠杆(交易所杠杆)', en: 'Trading Leverage (Exchange)' },
|
||||
btcEthLeverage: { zh: 'BTC/ETH 交易杠杆', en: 'BTC/ETH Trading Leverage' },
|
||||
btcEthLeverageDesc: { zh: '交易所开仓使用的杠杆倍数', en: 'Exchange leverage for opening positions' },
|
||||
altcoinLeverage: { zh: '山寨币交易杠杆', en: 'Altcoin Trading Leverage' },
|
||||
altcoinLeverageDesc: { zh: '交易所开仓使用的杠杆倍数', en: 'Exchange leverage for opening positions' },
|
||||
// Position value ratio (risk control) - CODE ENFORCED
|
||||
positionValueRatio: { zh: '仓位价值比例(代码强制)', en: 'Position Value Ratio (CODE ENFORCED)' },
|
||||
positionValueRatioDesc: { zh: '单仓位名义价值 / 账户净值,由代码强制执行', en: 'Position notional value / equity, enforced by code' },
|
||||
btcEthPositionValueRatio: { zh: 'BTC/ETH 仓位价值比例', en: 'BTC/ETH Position Value Ratio' },
|
||||
btcEthPositionValueRatioDesc: { zh: '单仓最大名义价值 = 净值 × 此值(代码强制)', en: 'Max position value = equity × this ratio (CODE ENFORCED)' },
|
||||
altcoinPositionValueRatio: { zh: '山寨币仓位价值比例', en: 'Altcoin Position Value Ratio' },
|
||||
altcoinPositionValueRatioDesc: { zh: '单仓最大名义价值 = 净值 × 此值(代码强制)', en: 'Max position value = equity × this ratio (CODE ENFORCED)' },
|
||||
riskParameters: { zh: '风险参数', en: 'Risk Parameters' },
|
||||
minRiskReward: { zh: '最小风险回报比', en: 'Min Risk/Reward Ratio' },
|
||||
minRiskRewardDesc: { zh: '开仓要求的最低盈亏比', en: 'Minimum profit ratio for opening' },
|
||||
maxMarginUsage: { zh: '最大保证金使用率', en: 'Max Margin Usage' },
|
||||
maxMarginUsageDesc: { zh: '保证金使用率上限', en: 'Maximum margin utilization' },
|
||||
maxPositionRatio: { zh: '单币最大仓位比', en: 'Max Position Ratio' },
|
||||
maxPositionRatioDesc: { zh: '相对账户净值的倍数', en: 'Multiple of account equity' },
|
||||
maxMarginUsage: { zh: '最大保证金使用率(代码强制)', en: 'Max Margin Usage (CODE ENFORCED)' },
|
||||
maxMarginUsageDesc: { zh: '保证金使用率上限,由代码强制执行', en: 'Maximum margin utilization, enforced by code' },
|
||||
entryRequirements: { zh: '开仓要求', en: 'Entry Requirements' },
|
||||
minPositionSize: { zh: '最小开仓金额', en: 'Min Position Size' },
|
||||
minPositionSizeDesc: { zh: 'USDT 最小名义价值', en: 'Minimum notional value in USDT' },
|
||||
@@ -57,7 +66,7 @@ export function RiskControlEditor({
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="grid grid-cols-1 gap-4 mb-4">
|
||||
<div
|
||||
className="p-4 rounded-lg"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139' }}
|
||||
@@ -70,14 +79,14 @@ export function RiskControlEditor({
|
||||
</p>
|
||||
<input
|
||||
type="number"
|
||||
value={config.max_positions}
|
||||
value={config.max_positions ?? 3}
|
||||
onChange={(e) =>
|
||||
updateField('max_positions', parseInt(e.target.value) || 3)
|
||||
}
|
||||
disabled={disabled}
|
||||
min={1}
|
||||
max={10}
|
||||
className="w-full px-3 py-2 rounded"
|
||||
className="w-32 px-3 py-2 rounded"
|
||||
style={{
|
||||
background: '#1E2329',
|
||||
border: '1px solid #2B3139',
|
||||
@@ -85,7 +94,15 @@ export function RiskControlEditor({
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Trading Leverage (Exchange) */}
|
||||
<div className="mb-2">
|
||||
<p className="text-xs font-medium mb-2" style={{ color: '#F0B90B' }}>
|
||||
{t('tradingLeverage')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4 mb-4">
|
||||
<div
|
||||
className="p-4 rounded-lg"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139' }}
|
||||
@@ -93,10 +110,13 @@ export function RiskControlEditor({
|
||||
<label className="block text-sm mb-1" style={{ color: '#EAECEF' }}>
|
||||
{t('btcEthLeverage')}
|
||||
</label>
|
||||
<p className="text-xs mb-2" style={{ color: '#848E9C' }}>
|
||||
{t('btcEthLeverageDesc')}
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
value={config.btc_eth_max_leverage}
|
||||
value={config.btc_eth_max_leverage ?? 5}
|
||||
onChange={(e) =>
|
||||
updateField('btc_eth_max_leverage', parseInt(e.target.value))
|
||||
}
|
||||
@@ -109,7 +129,7 @@ export function RiskControlEditor({
|
||||
className="w-12 text-center font-mono"
|
||||
style={{ color: '#F0B90B' }}
|
||||
>
|
||||
{config.btc_eth_max_leverage}x
|
||||
{config.btc_eth_max_leverage ?? 5}x
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -121,10 +141,13 @@ export function RiskControlEditor({
|
||||
<label className="block text-sm mb-1" style={{ color: '#EAECEF' }}>
|
||||
{t('altcoinLeverage')}
|
||||
</label>
|
||||
<p className="text-xs mb-2" style={{ color: '#848E9C' }}>
|
||||
{t('altcoinLeverageDesc')}
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
value={config.altcoin_max_leverage}
|
||||
value={config.altcoin_max_leverage ?? 5}
|
||||
onChange={(e) =>
|
||||
updateField('altcoin_max_leverage', parseInt(e.target.value))
|
||||
}
|
||||
@@ -137,7 +160,82 @@ export function RiskControlEditor({
|
||||
className="w-12 text-center font-mono"
|
||||
style={{ color: '#F0B90B' }}
|
||||
>
|
||||
{config.altcoin_max_leverage}x
|
||||
{config.altcoin_max_leverage ?? 5}x
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Position Value Ratio (Risk Control - CODE ENFORCED) */}
|
||||
<div className="mb-2">
|
||||
<p className="text-xs font-medium" style={{ color: '#0ECB81' }}>
|
||||
{t('positionValueRatio')}
|
||||
</p>
|
||||
<p className="text-xs mt-1" style={{ color: '#848E9C' }}>
|
||||
{t('positionValueRatioDesc')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div
|
||||
className="p-4 rounded-lg"
|
||||
style={{ background: '#0B0E11', border: '1px solid #0ECB81' }}
|
||||
>
|
||||
<label className="block text-sm mb-1" style={{ color: '#EAECEF' }}>
|
||||
{t('btcEthPositionValueRatio')}
|
||||
</label>
|
||||
<p className="text-xs mb-2" style={{ color: '#848E9C' }}>
|
||||
{t('btcEthPositionValueRatioDesc')}
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
value={config.btc_eth_max_position_value_ratio ?? 5}
|
||||
onChange={(e) =>
|
||||
updateField('btc_eth_max_position_value_ratio', parseFloat(e.target.value))
|
||||
}
|
||||
disabled={disabled}
|
||||
min={0.5}
|
||||
max={10}
|
||||
step={0.5}
|
||||
className="flex-1 accent-green-500"
|
||||
/>
|
||||
<span
|
||||
className="w-12 text-center font-mono"
|
||||
style={{ color: '#0ECB81' }}
|
||||
>
|
||||
{config.btc_eth_max_position_value_ratio ?? 5}x
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="p-4 rounded-lg"
|
||||
style={{ background: '#0B0E11', border: '1px solid #0ECB81' }}
|
||||
>
|
||||
<label className="block text-sm mb-1" style={{ color: '#EAECEF' }}>
|
||||
{t('altcoinPositionValueRatio')}
|
||||
</label>
|
||||
<p className="text-xs mb-2" style={{ color: '#848E9C' }}>
|
||||
{t('altcoinPositionValueRatioDesc')}
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
value={config.altcoin_max_position_value_ratio ?? 1}
|
||||
onChange={(e) =>
|
||||
updateField('altcoin_max_position_value_ratio', parseFloat(e.target.value))
|
||||
}
|
||||
disabled={disabled}
|
||||
min={0.5}
|
||||
max={10}
|
||||
step={0.5}
|
||||
className="flex-1 accent-green-500"
|
||||
/>
|
||||
<span
|
||||
className="w-12 text-center font-mono"
|
||||
style={{ color: '#0ECB81' }}
|
||||
>
|
||||
{config.altcoin_max_position_value_ratio ?? 1}x
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,7 +251,7 @@ export function RiskControlEditor({
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div
|
||||
className="p-4 rounded-lg"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139' }}
|
||||
@@ -168,7 +266,7 @@ export function RiskControlEditor({
|
||||
<span style={{ color: '#848E9C' }}>1:</span>
|
||||
<input
|
||||
type="number"
|
||||
value={config.min_risk_reward_ratio}
|
||||
value={config.min_risk_reward_ratio ?? 3}
|
||||
onChange={(e) =>
|
||||
updateField('min_risk_reward_ratio', parseFloat(e.target.value) || 3)
|
||||
}
|
||||
@@ -188,7 +286,7 @@ export function RiskControlEditor({
|
||||
|
||||
<div
|
||||
className="p-4 rounded-lg"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139' }}
|
||||
style={{ background: '#0B0E11', border: '1px solid #0ECB81' }}
|
||||
>
|
||||
<label className="block text-sm mb-1" style={{ color: '#EAECEF' }}>
|
||||
{t('maxMarginUsage')}
|
||||
@@ -199,51 +297,17 @@ export function RiskControlEditor({
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
value={config.max_margin_usage * 100}
|
||||
value={(config.max_margin_usage ?? 0.9) * 100}
|
||||
onChange={(e) =>
|
||||
updateField('max_margin_usage', parseInt(e.target.value) / 100)
|
||||
}
|
||||
disabled={disabled}
|
||||
min={10}
|
||||
max={100}
|
||||
className="flex-1 accent-red-500"
|
||||
className="flex-1 accent-green-500"
|
||||
/>
|
||||
<span className="w-12 text-center font-mono" style={{ color: '#F6465D' }}>
|
||||
{Math.round(config.max_margin_usage * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="p-4 rounded-lg"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139' }}
|
||||
>
|
||||
<label className="block text-sm mb-1" style={{ color: '#EAECEF' }}>
|
||||
{t('maxPositionRatio')}
|
||||
</label>
|
||||
<p className="text-xs mb-2" style={{ color: '#848E9C' }}>
|
||||
{t('maxPositionRatioDesc')}
|
||||
</p>
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
type="number"
|
||||
value={config.max_position_ratio}
|
||||
onChange={(e) =>
|
||||
updateField('max_position_ratio', parseFloat(e.target.value) || 1.5)
|
||||
}
|
||||
disabled={disabled}
|
||||
min={0.5}
|
||||
max={5}
|
||||
step={0.1}
|
||||
className="w-20 px-3 py-2 rounded"
|
||||
style={{
|
||||
background: '#1E2329',
|
||||
border: '1px solid #2B3139',
|
||||
color: '#EAECEF',
|
||||
}}
|
||||
/>
|
||||
<span className="ml-2" style={{ color: '#848E9C' }}>
|
||||
x
|
||||
<span className="w-12 text-center font-mono" style={{ color: '#0ECB81' }}>
|
||||
{Math.round((config.max_margin_usage ?? 0.9) * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -273,7 +337,7 @@ export function RiskControlEditor({
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
type="number"
|
||||
value={config.min_position_size}
|
||||
value={config.min_position_size ?? 12}
|
||||
onChange={(e) =>
|
||||
updateField('min_position_size', parseFloat(e.target.value) || 12)
|
||||
}
|
||||
@@ -306,7 +370,7 @@ export function RiskControlEditor({
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
value={config.min_confidence}
|
||||
value={config.min_confidence ?? 75}
|
||||
onChange={(e) =>
|
||||
updateField('min_confidence', parseInt(e.target.value))
|
||||
}
|
||||
@@ -316,7 +380,7 @@ export function RiskControlEditor({
|
||||
className="flex-1 accent-green-500"
|
||||
/>
|
||||
<span className="w-12 text-center font-mono" style={{ color: '#0ECB81' }}>
|
||||
{config.min_confidence}
|
||||
{config.min_confidence ?? 75}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user