주가 표시형식 수정
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
type ProcessMonitorDto,
|
||||
type SystemMonitorDto,
|
||||
} from '../utils/backendApi';
|
||||
import { formatUpbitKrwPrice } from '../utils/safeFormat';
|
||||
import DashboardGauge from './dashboard/DashboardGauge';
|
||||
import DashboardSegmentBar from './dashboard/DashboardSegmentBar';
|
||||
import DashboardSparkChart from './dashboard/DashboardSparkChart';
|
||||
@@ -339,7 +340,7 @@ const DashboardPage: React.FC<Props> = ({ theme, onGoChart }) => {
|
||||
<button type="button" className="gc-signal-main" onClick={() => onGoChart?.(s.market)}>
|
||||
<strong>{buy ? 'BUY' : 'SELL'}</strong>
|
||||
<span>{s.market.replace('KRW-', '')}</span>
|
||||
<span className="gc-signal-price">@ {s.price?.toLocaleString('ko-KR')}</span>
|
||||
<span className="gc-signal-price">@ {s.price != null ? formatUpbitKrwPrice(s.price) : ''}</span>
|
||||
</button>
|
||||
<span className="gc-signal-time">{s.createdAt?.slice(11, 16) ?? ''}</span>
|
||||
</li>
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useRef, useEffect, useCallback, useState } from 'react';
|
||||
import type { ChartManager } from '../utils/ChartManager';
|
||||
import type { Drawing, DrawingPoint, DrawingToolId, Theme } from '../types';
|
||||
import { formatUnixDateTime } from '../utils/timezone';
|
||||
import { formatUpbitKrwPrice } from '../utils/safeFormat';
|
||||
|
||||
// ─── Hit-test ──────────────────────────────────────────────────────────────
|
||||
const HIT_RADIUS = 7; // px (CSS 좌표)
|
||||
@@ -1088,7 +1089,7 @@ function renderInfoLine(ctx: CanvasRenderingContext2D, d: Drawing, m: ChartManag
|
||||
ctx.strokeStyle = d.color; ctx.lineWidth = d.lineWidth ?? 1;
|
||||
ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(cssW, y); ctx.stroke();
|
||||
const price = d.points[0].price;
|
||||
const label = price >= 1000 ? price.toLocaleString('ko-KR') : price.toFixed(4);
|
||||
const label = formatUpbitKrwPrice(price);
|
||||
ctx.font = 'bold 10px sans-serif';
|
||||
const tw = ctx.measureText(label).width + 8;
|
||||
ctx.fillStyle = d.color;
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
getFavorites, saveFavorites, toggleFavorite,
|
||||
getHoldings, addHolding, removeHolding,
|
||||
} from '../utils/marketStorage';
|
||||
import { formatUpbitKrwPrice } from '../utils/safeFormat';
|
||||
// ─── 타입 ──────────────────────────────────────────────────────────────────
|
||||
type Tab = 'krw' | 'btc' | 'hold' | 'fav';
|
||||
type SortKey = 'name' | 'price' | 'change';
|
||||
@@ -29,12 +30,7 @@ export interface MarketPanelProps {
|
||||
|
||||
// ─── 가격 포맷 헬퍼 ────────────────────────────────────────────────────────
|
||||
function fmtKrw(price: number | null | undefined): string {
|
||||
if (price == null || !isFinite(price)) return '-';
|
||||
if (price >= 1_000_000) return price.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
|
||||
if (price >= 1_000) return price.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
|
||||
if (price >= 1) return price.toLocaleString('ko-KR', { maximumFractionDigits: 2 });
|
||||
if (price >= 0.01) return price.toFixed(4);
|
||||
return price.toFixed(8);
|
||||
return formatUpbitKrwPrice(price, '-');
|
||||
}
|
||||
|
||||
function fmtUsd(krwPrice: number | null | undefined, rate: number): string {
|
||||
|
||||
@@ -7,12 +7,11 @@ import { formatNowClock, useDisplayTimezone } from '../utils/timezone';
|
||||
import type { OrderbookDisplayUnit, WsStatus } from '../hooks/useUpbitOrderbook';
|
||||
import type { RecentTrade } from '../hooks/useUpbitRecentTrades';
|
||||
import { getKoreanName } from '../utils/marketNameCache';
|
||||
import { formatUpbitKrwPrice } from '../utils/safeFormat';
|
||||
|
||||
function fmtPrice(p: number): string {
|
||||
if (p == null || !isFinite(p)) return '-';
|
||||
if (p >= 1_000) return p.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
|
||||
if (p >= 1) return p.toFixed(2);
|
||||
return p.toFixed(6);
|
||||
return formatUpbitKrwPrice(p, '-');
|
||||
}
|
||||
|
||||
function fmtSize(s: number): string {
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { useState } from 'react';
|
||||
import { useDraggablePanel } from '../hooks/useDraggablePanel';
|
||||
import { placePaperOrder, placeLiveOrder, loadLiveSummary } from '../utils/backendApi';
|
||||
import { formatSignalTime } from '../utils/tradeSignalDisplay';
|
||||
import { formatUpbitKrwPrice } from '../utils/safeFormat';
|
||||
import { TRADE_BUY_COLOR, TRADE_SELL_COLOR } from '../utils/tradeSignalColors';
|
||||
import { useTradeAlertTimeFormat } from '../utils/tradeAlertTimeFormat';
|
||||
|
||||
@@ -30,7 +31,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const fmt = (n: number): string =>
|
||||
n > 0 ? n.toLocaleString('ko-KR', { maximumFractionDigits: 0 }) : '0';
|
||||
n > 0 ? formatUpbitKrwPrice(n, '0') : '0';
|
||||
|
||||
|
||||
function execLabel(type?: string, candleType?: string): string {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { getKoreanName } from '../utils/marketNameCache';
|
||||
import { MarketSearchPanel } from './MarketSearchPanel';
|
||||
import type { TradeOrderFillRequest } from '../types';
|
||||
import { placePaperOrder } from '../utils/backendApi';
|
||||
import { coerceFiniteNumber } from '../utils/safeFormat';
|
||||
import { coerceFiniteNumber, formatUpbitKrwPrice, upbitKrwTickSize } from '../utils/safeFormat';
|
||||
|
||||
export type OrderKind = 'limit' | 'market' | 'stop_limit';
|
||||
|
||||
@@ -39,7 +39,7 @@ export interface TradeOrderPanelProps {
|
||||
|
||||
export function fmtKrw(n: number): string {
|
||||
if (!Number.isFinite(n)) return '0';
|
||||
return Math.round(n).toLocaleString('ko-KR');
|
||||
return formatUpbitKrwPrice(n, '0');
|
||||
}
|
||||
|
||||
function parseNum(s: string): number {
|
||||
@@ -47,11 +47,19 @@ function parseNum(s: string): number {
|
||||
return Number.isFinite(v) ? v : 0;
|
||||
}
|
||||
|
||||
/** KRW 가격: 숫자만 허용, 천 단위 쉼표 표시 */
|
||||
/** KRW 가격: 숫자·소수점(필요 시)만 허용, 업비트 규칙으로 표시 */
|
||||
function sanitizePriceInput(raw: string): string {
|
||||
const digits = raw.replace(/\D/g, '');
|
||||
if (!digits) return '';
|
||||
return Number(digits).toLocaleString('ko-KR');
|
||||
const cleaned = raw.replace(/[^\d.]/g, '');
|
||||
if (!cleaned) return '';
|
||||
const n = Number(cleaned);
|
||||
if (!Number.isFinite(n)) return '';
|
||||
return formatUpbitKrwPrice(n, cleaned);
|
||||
}
|
||||
|
||||
/** 현재 가격에 맞는 호가 단위만큼 증감 */
|
||||
export function stepPriceByTick(price: number, direction: 1 | -1): number {
|
||||
const tick = upbitKrwTickSize(price);
|
||||
return Math.round((price + direction * tick) / tick) * tick;
|
||||
}
|
||||
|
||||
/** 주문 수량: 숫자와 소수점(1개)만 허용 */
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useRef, useEffect, useLayoutEffect, useState, useCallback } from
|
||||
import type { MouseEventParams, Time } from 'lightweight-charts';
|
||||
import type { OHLCVBar, ChartType, Theme, IndicatorConfig, LegendData, Drawing, ChartMode, Timeframe } from '../types';
|
||||
import { ChartManager } from '../utils/ChartManager';
|
||||
import { formatUpbitKrwPrice } from '../utils/safeFormat';
|
||||
import { useChartTimeFormat } from '../utils/chartTimeFormat';
|
||||
import { setIndicatorChartContext } from '../utils/indicatorRegistry';
|
||||
import { DISPLAY_COUNT } from '../hooks/useUpbitData';
|
||||
@@ -1675,8 +1676,7 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
container.style.cursor = isHit ? 'pointer' : '';
|
||||
}, []);
|
||||
|
||||
const fmtCtxPrice = (p: number) =>
|
||||
p >= 1000 ? Math.round(p).toLocaleString('ko-KR') : p.toFixed(p >= 1 ? 2 : 6);
|
||||
const fmtCtxPrice = (p: number) => formatUpbitKrwPrice(p);
|
||||
|
||||
const closeCtxAndRequest = useCallback((side: 'buy' | 'sell') => {
|
||||
if (!ctxMenu || !market) return;
|
||||
|
||||
@@ -19,17 +19,18 @@ import {
|
||||
drawdownSeries,
|
||||
} from '../../utils/analysisReportMetrics';
|
||||
import { repairUtf8Mojibake } from '../../utils/textEncoding';
|
||||
import { formatUpbitKrwPrice } from '../../utils/safeFormat';
|
||||
|
||||
/* ── 포맷 유틸 ── */
|
||||
const pct = (v: number, dec = 2) => `${v >= 0 ? '+' : ''}${(v * 100).toFixed(dec)}%`;
|
||||
const pctAbs= (v: number, dec = 1) => `${(v * 100).toFixed(dec)}%`;
|
||||
const num = (v: number, dec = 2) => (isFinite(v) ? v.toFixed(dec) : '—');
|
||||
const wonFmt= (v: number) => {
|
||||
const wonFmt = (v: number) => {
|
||||
const abs = Math.abs(v);
|
||||
const sign = v < 0 ? '-' : v > 0 ? '+' : '';
|
||||
if (abs >= 1e8) return `${sign}${(abs / 1e8).toFixed(1)}억`;
|
||||
if (abs >= 1e4) return `${sign}${(abs / 1e4).toFixed(0)}만`;
|
||||
return `${sign}${abs.toLocaleString('ko-KR')}원`;
|
||||
return `${sign}${formatUpbitKrwPrice(abs, '0')}원`;
|
||||
};
|
||||
const colorCls = (v: number) => (v > 0 ? 'up' : v < 0 ? 'down' : '');
|
||||
|
||||
@@ -617,8 +618,8 @@ function LogsView({ ctx }: { ctx: AnalysisReportContext }) {
|
||||
<td>{r.dateTime}</td>
|
||||
<td className="qcc-sym">{r.symbol.replace('KRW-', 'KRW-')}</td>
|
||||
<td className="qcc-side">{r.side}</td>
|
||||
<td className="qcc-num">{r.entryPrice.toLocaleString('ko-KR')}</td>
|
||||
<td className="qcc-num">{r.exitPrice.toLocaleString('ko-KR')}</td>
|
||||
<td className="qcc-num">{formatUpbitKrwPrice(r.entryPrice)}</td>
|
||||
<td className="qcc-num">{formatUpbitKrwPrice(r.exitPrice)}</td>
|
||||
<td className="qcc-num">{r.qty.toFixed(3)}</td>
|
||||
<td className={r.pnlPct >= 0 ? 'up' : 'down'}>{r.pnlPct >= 0 ? '+' : ''}{r.pnlPct.toFixed(1)}%</td>
|
||||
<td className="qcc-dur">{r.durationSec > 0 ? fmtDuration(r.durationSec) : '—'}</td>
|
||||
@@ -658,7 +659,7 @@ function AllocationView({ ctx }: { ctx: AnalysisReportContext }) {
|
||||
<span className="qcc-alloc-dot" style={{ background: sl.color }} />
|
||||
<span className="qcc-alloc-sym">{sl.symbol.replace('KRW-', 'KRW-')}</span>
|
||||
<span className="qcc-alloc-pct">{(sl.pct * 100).toFixed(2)}%</span>
|
||||
<span className="qcc-alloc-krw">₩{Math.round(sl.capitalKrw).toLocaleString('ko-KR')}</span>
|
||||
<span className="qcc-alloc-krw">₩{formatUpbitKrwPrice(sl.capitalKrw)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { BacktestAnalysis } from '../../utils/backendApi';
|
||||
import BacktestSparkline from './BacktestSparkline';
|
||||
import type { EquityPoint } from '../../utils/backtestEquity';
|
||||
import { krw, pct, pctAbs } from '../../utils/backtestUiUtils';
|
||||
import { formatUpbitKrwPrice } from '../../utils/safeFormat';
|
||||
|
||||
interface Props {
|
||||
analysis: BacktestAnalysis | null;
|
||||
@@ -21,7 +22,7 @@ interface Props {
|
||||
const num = (v: number, dec = 2) => (isFinite(v) ? v.toFixed(dec) : '–');
|
||||
|
||||
const fmtWon = (v: number) =>
|
||||
isFinite(v) ? `₩${Math.round(v).toLocaleString('ko-KR')}` : '–';
|
||||
isFinite(v) ? `₩${formatUpbitKrwPrice(v, '–')}` : '–';
|
||||
|
||||
function MetricCell({
|
||||
label,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useUpbitOrderbook } from '../../hooks/useUpbitOrderbook';
|
||||
import { coerceFiniteNumber, safeToFixed } from '../../utils/safeFormat';
|
||||
import { coerceFiniteNumber, safeToFixed, formatUpbitKrwPrice } from '../../utils/safeFormat';
|
||||
|
||||
interface Props {
|
||||
market: string;
|
||||
@@ -14,8 +14,7 @@ interface Props {
|
||||
|
||||
function fmtPrice(p: unknown): string {
|
||||
const n = coerceFiniteNumber(p);
|
||||
if (n == null) return '-';
|
||||
return n >= 1000 ? n.toLocaleString('ko-KR', { maximumFractionDigits: 0 }) : safeToFixed(n, 4);
|
||||
return formatUpbitKrwPrice(n, '-');
|
||||
}
|
||||
|
||||
function fmtSize(s: unknown): string {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import type { TrendSearchResultDto } from '../../utils/trendSearchApi';
|
||||
import { formatUpbitKrwPrice } from '../../utils/safeFormat';
|
||||
|
||||
interface Props {
|
||||
results: TrendSearchResultDto[];
|
||||
@@ -10,9 +11,7 @@ interface Props {
|
||||
}
|
||||
|
||||
function fmtPrice(n: number): string {
|
||||
if (n >= 1_000_000) return n.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
|
||||
if (n >= 100) return n.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
|
||||
return n.toLocaleString('ko-KR', { maximumFractionDigits: 4 });
|
||||
return formatUpbitKrwPrice(n, '-');
|
||||
}
|
||||
|
||||
function fmtPct(n: number): string {
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import React, { memo, useEffect, useRef, useState } from 'react';
|
||||
import type { ChangeDir, TickerData } from '../../hooks/useMarketTicker';
|
||||
import { coerceFiniteNumber, safePercentFromRate, safeToFixed } from '../../utils/safeFormat';
|
||||
import { coerceFiniteNumber, safePercentFromRate, formatUpbitKrwPrice } from '../../utils/safeFormat';
|
||||
|
||||
function fmtKrw(price: number | null | undefined | unknown): string {
|
||||
const p = coerceFiniteNumber(price);
|
||||
if (p == null) return '-';
|
||||
if (p >= 1_000_000) return p.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
|
||||
if (p >= 1_000) return p.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
|
||||
if (p >= 1) return p.toLocaleString('ko-KR', { maximumFractionDigits: 2 });
|
||||
if (p >= 0.01) return safeToFixed(p, 4, '-');
|
||||
return safeToFixed(p, 8, '-');
|
||||
return formatUpbitKrwPrice(p, '-');
|
||||
}
|
||||
|
||||
function fmtPct(rate: number | null | undefined | unknown): string {
|
||||
|
||||
Reference in New Issue
Block a user