goldenChat base source add

This commit is contained in:
aidev
2026-05-23 15:11:48 +09:00
commit a4ea7762b5
2081 changed files with 1155760 additions and 0 deletions
@@ -0,0 +1,227 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 앱 전역 차트 기본 설정.
*
* <p>프론트엔드 코드에 하드코딩된 다음 값들을 DB 로 대체한다:
* <ul>
* <li>기본 심볼 (DEFAULT_STATE.symbol → 'KRW-BTC')</li>
* <li>기본 타임프레임 (DEFAULT_STATE.timeframe → '1D')</li>
* <li>기본 차트 타입 ('candlestick')</li>
* <li>기본 테마 ('dark')</li>
* <li>기본 로그 스케일 (false)</li>
* <li>기본 레이아웃 ID ('1')</li>
* <li>캔들 색상 (DEFAULT_MAIN_CHART_STYLE)</li>
* <li>멀티차트 동기화 옵션 (DEFAULT_SYNC)</li>
* </ul>
*/
@Entity
@Table(name = "gc_app_settings")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcAppSettings {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "device_id", length = 100, unique = true)
private String deviceId;
@Column(name = "user_id", unique = true)
private Long userId;
@Column(name = "default_symbol", length = 50, nullable = false)
@Builder.Default
private String defaultSymbol = "KRW-BTC";
@Column(name = "default_timeframe", length = 10, nullable = false)
@Builder.Default
private String defaultTimeframe = "1D";
@Column(name = "default_chart_type", length = 20, nullable = false)
@Builder.Default
private String defaultChartType = "candlestick";
@Column(name = "default_theme", length = 20, nullable = false)
@Builder.Default
private String defaultTheme = "dark";
@Column(name = "default_log_scale", nullable = false)
@Builder.Default
private Boolean defaultLogScale = false;
@Column(name = "default_layout_id", length = 20, nullable = false)
@Builder.Default
private String defaultLayoutId = "1";
/** 차트·UI 시간 표시 IANA 시간대 */
@Column(name = "display_timezone", length = 64, nullable = false)
@Builder.Default
private String displayTimezone = "Asia/Seoul";
/** 캔들 색상 JSON (frontend MainChartStyle 구조) */
@Column(name = "main_chart_style_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
private String mainChartStyleJson;
/** 멀티차트 동기화 옵션 JSON (frontend SyncOptions 구조) */
@Column(name = "sync_options_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
private String syncOptionsJson;
/** 백테스팅 완료 시 결과 팝업 자동 표시 여부 (기본 true) */
@Column(name = "bt_auto_popup", nullable = false)
@Builder.Default
private Boolean btAutoPopup = true;
/** 백테스팅 매수/매도 마커에 금액 표시 여부 (기본 true) */
@Column(name = "bt_show_price", nullable = false)
@Builder.Default
private Boolean btShowPrice = true;
/** 보조지표 우측 가격축 라벨·설명·금액 하이라이트 (기본 true) */
@Column(name = "chart_series_price_labels", nullable = false)
@Builder.Default
private Boolean chartSeriesPriceLabels = true;
/** 차트 하단 거래량 바 표시 (기본 true) */
@Column(name = "chart_volume_visible", nullable = false)
@Builder.Default
private Boolean chartVolumeVisible = true;
/** 차트 상단 범례(tv-legend) 항목별 표시 옵션 JSON */
@Column(name = "chart_legend_options_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
private String chartLegendOptionsJson;
/** 매매 시그널 발생 시 알림 팝업 표시 여부 (기본 true) */
@Column(name = "trade_alert_popup", nullable = false)
@Builder.Default
private Boolean tradeAlertPopup = true;
/** 매매 시그널 알림 사운드 재생 여부 */
@Column(name = "trade_alert_sound_enabled", nullable = false)
@Builder.Default
private Boolean tradeAlertSoundEnabled = true;
/** 매매 시그널 알림음 ID (bell, chime, silent 등) */
@Column(name = "trade_alert_sound", nullable = false, length = 32)
@Builder.Default
private String tradeAlertSound = "bell";
/** 알림 팝업 위치: right | left | bottom */
@Column(name = "trade_alert_popup_position", nullable = false, length = 10)
@Builder.Default
private String tradeAlertPopupPosition = "right";
/** 알림 팝업 배치: stack | grid | strip | single */
@Column(name = "trade_alert_popup_layout", nullable = false, length = 10)
@Builder.Default
private String tradeAlertPopupLayout = "stack";
/** 그리드 배치 시 열 개수 (2~4) */
@Column(name = "trade_alert_popup_grid_cols", nullable = false)
@Builder.Default
private Integer tradeAlertPopupGridCols = 2;
/** 실시간 전략 체크 마스터 ON/OFF — ON 이면 DB 관심종목 전체가 체크 대상 */
@Column(name = "live_strategy_check", nullable = false)
@Builder.Default
private Boolean liveStrategyCheck = false;
/** 관심종목에 공통 적용할 전략 ID */
@Column(name = "live_strategy_id")
private Long liveStrategyId;
@Column(name = "live_execution_type", nullable = false, length = 30)
@Builder.Default
private String liveExecutionType = "CANDLE_CLOSE";
@Column(name = "live_position_mode", nullable = false, length = 20)
@Builder.Default
private String livePositionMode = "LONG_ONLY";
/** 모의투자 마스터 ON/OFF */
@Column(name = "paper_trading_enabled", nullable = false)
@Builder.Default
private Boolean paperTradingEnabled = true;
@Column(name = "paper_initial_capital", nullable = false, precision = 20, scale = 2)
@Builder.Default
private BigDecimal paperInitialCapital = BigDecimal.valueOf(10_000_000);
@Column(name = "paper_fee_rate_pct", nullable = false, precision = 8, scale = 4)
@Builder.Default
private BigDecimal paperFeeRatePct = BigDecimal.valueOf(0.05);
@Column(name = "paper_slippage_pct", nullable = false, precision = 8, scale = 4)
@Builder.Default
private BigDecimal paperSlippagePct = BigDecimal.ZERO;
@Column(name = "paper_min_order_krw", nullable = false, precision = 20, scale = 2)
@Builder.Default
private BigDecimal paperMinOrderKrw = BigDecimal.valueOf(5000);
/** 실시간 전략 시그널 시 자동 모의매매 */
@Column(name = "paper_auto_trade_enabled", nullable = false)
@Builder.Default
private Boolean paperAutoTradeEnabled = false;
@Column(name = "paper_auto_trade_budget_pct", nullable = false, precision = 8, scale = 4)
@Builder.Default
private BigDecimal paperAutoTradeBudgetPct = BigDecimal.valueOf(95);
/** PAPER | LIVE | BOTH — 자동매매 실행 대상 */
@Column(name = "trading_mode", nullable = false, length = 10)
@Builder.Default
private String tradingMode = "PAPER";
/** 실거래(Upbit API) 자동매매 ON */
@Column(name = "live_auto_trade_enabled", nullable = false)
@Builder.Default
private Boolean liveAutoTradeEnabled = false;
@Column(name = "upbit_access_key", length = 128)
private String upbitAccessKey;
@Column(name = "upbit_secret_key", length = 256)
private String upbitSecretKey;
/** BACKEND_STOMP | UPBIT_DIRECT */
@Column(name = "chart_realtime_source", nullable = false, length = 20)
@Builder.Default
private String chartRealtimeSource = "BACKEND_STOMP";
@Column(name = "live_auto_trade_budget_pct", nullable = false, precision = 8, scale = 4)
@Builder.Default
private BigDecimal liveAutoTradeBudgetPct = BigDecimal.valueOf(95);
@Column(name = "fcm_push_enabled", nullable = false)
@Builder.Default
private Boolean fcmPushEnabled = false;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,48 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Entity
@Table(name = "gc_backtest_result")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcBacktestResult {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "device_id", length = 100) private String deviceId;
@Column(name = "strategy_id") private Long strategyId;
@Column(name = "strategy_name", length = 200) private String strategyName;
@Column(name = "symbol", length = 50) private String symbol;
@Column(name = "timeframe", length = 10) private String timeframe;
@Column(name = "bar_count") private Integer barCount;
@Column(name = "from_time") private Long fromTime;
@Column(name = "to_time") private Long toTime;
@Column(name = "settings_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON) private String settingsJson;
@Column(name = "signals_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON) private String signalsJson;
@Column(name = "analysis_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON) private String analysisJson;
@Column(name = "total_return", precision = 12, scale = 4) private BigDecimal totalReturn;
@Column(name = "win_rate", precision = 6, scale = 4) private BigDecimal winRate;
@Column(name = "total_trades") private Integer totalTrades;
@Column(name = "max_drawdown", precision = 12, scale = 4) private BigDecimal maxDrawdown;
@Column(name = "sharpe_ratio", precision = 10, scale = 4) private BigDecimal sharpeRatio;
@Column(name = "final_equity", precision = 20, scale = 2) private BigDecimal finalEquity;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@PrePersist protected void onCreate() { createdAt = LocalDateTime.now(); }
}
@@ -0,0 +1,133 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 백테스팅 설정 엔티티.
* Ta4j 의 비용 모델·손절/익절/트레일링 스탑·진입가격·재진입 규칙 등을 저장.
*/
@Entity
@Table(name = "gc_backtest_settings")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcBacktestSettings {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "device_id", length = 100)
private String deviceId;
// ── 자본 설정 ──────────────────────────────────────────────────────────────
@Column(name = "initial_capital", nullable = false, precision = 20, scale = 2)
@Builder.Default
private BigDecimal initialCapital = new BigDecimal("10000000.00");
// ── 비용 모델 ──────────────────────────────────────────────────────────────
/** LINEAR | ZERO */
@Column(name = "commission_type", nullable = false, length = 20)
@Builder.Default
private String commissionType = "LINEAR";
@Column(name = "commission_rate", nullable = false, precision = 8, scale = 5)
@Builder.Default
private BigDecimal commissionRate = new BigDecimal("0.00150");
@Column(name = "slippage_rate", nullable = false, precision = 8, scale = 5)
@Builder.Default
private BigDecimal slippageRate = new BigDecimal("0.00050");
// ── 진입/청산 가격 ─────────────────────────────────────────────────────────
/** CLOSE | NEXT_OPEN */
@Column(name = "entry_price_type", nullable = false, length = 20)
@Builder.Default
private String entryPriceType = "CLOSE";
/** CLOSE | NEXT_OPEN */
@Column(name = "exit_price_type", nullable = false, length = 20)
@Builder.Default
private String exitPriceType = "CLOSE";
// ── 포지션 방향 ────────────────────────────────────────────────────────────
/** LONG | SHORT | BOTH */
@Column(name = "position_direction", nullable = false, length = 10)
@Builder.Default
private String positionDirection = "LONG";
// ── 거래 규모 ──────────────────────────────────────────────────────────────
/** CAPITAL_PCT | FIXED_AMOUNT */
@Column(name = "trade_size_type", nullable = false, length = 20)
@Builder.Default
private String tradeSizeType = "CAPITAL_PCT";
@Column(name = "trade_size_value", nullable = false, precision = 10, scale = 4)
@Builder.Default
private BigDecimal tradeSizeValue = new BigDecimal("100.0000");
// ── 손절 ───────────────────────────────────────────────────────────────────
@Column(name = "stop_loss_enabled", nullable = false)
@Builder.Default
private Boolean stopLossEnabled = false;
@Column(name = "stop_loss_pct", nullable = false, precision = 6, scale = 3)
@Builder.Default
private BigDecimal stopLossPct = new BigDecimal("2.000");
// ── 익절 ───────────────────────────────────────────────────────────────────
@Column(name = "take_profit_enabled", nullable = false)
@Builder.Default
private Boolean takeProfitEnabled = false;
@Column(name = "take_profit_pct", nullable = false, precision = 6, scale = 3)
@Builder.Default
private BigDecimal takeProfitPct = new BigDecimal("5.000");
// ── 트레일링 스탑 ──────────────────────────────────────────────────────────
@Column(name = "trailing_stop_enabled", nullable = false)
@Builder.Default
private Boolean trailingStopEnabled = false;
@Column(name = "trailing_stop_pct", nullable = false, precision = 6, scale = 3)
@Builder.Default
private BigDecimal trailingStopPct = new BigDecimal("2.000");
// ── 재진입 제어 ────────────────────────────────────────────────────────────
@Column(name = "reentry_wait_bars", nullable = false)
@Builder.Default
private Integer reentryWaitBars = 0;
@Column(name = "max_open_trades", nullable = false)
@Builder.Default
private Integer maxOpenTrades = 1;
// ── 포지션 종속성 모드 ─────────────────────────────────────────────────────
/** LONG_ONLY | SIGNAL_ONLY */
@Column(name = "position_mode", nullable = false, length = 20)
@Builder.Default
private String positionMode = "LONG_ONLY";
// ── 분할 청산 ──────────────────────────────────────────────────────────────
@Column(name = "partial_exit_enabled", nullable = false)
@Builder.Default
private Boolean partialExitEnabled = false;
@Column(name = "partial_exit_pct", nullable = false, precision = 6, scale = 3)
@Builder.Default
private BigDecimal partialExitPct = new BigDecimal("50.000");
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() { createdAt = updatedAt = LocalDateTime.now(); }
@PreUpdate
protected void onUpdate() { updatedAt = LocalDateTime.now(); }
}
@@ -0,0 +1,121 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
import java.time.LocalDateTime;
/**
* 차트 슬롯 설정.
* 멀티차트 레이아웃 내 각 슬롯의 모든 설정값을 저장.
*/
@Entity
@Table(name = "gc_chart_slot",
uniqueConstraints = @UniqueConstraint(name = "uk_slot_workspace_index",
columnNames = {"workspace_id", "slot_index"}))
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcChartSlot {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "workspace_id", nullable = false)
private GcChartWorkspace workspace;
/** 슬롯 인덱스 (0-based) */
@Column(name = "slot_index", nullable = false)
private Integer slotIndex;
/** 종목 코드 (e.g. "KRW-BTC", "AAPL") */
@Column(name = "symbol", length = 50)
private String symbol;
/** 타임프레임 (1m/5m/15m/30m/1h/4h/1D/1W/1M) */
@Column(name = "timeframe", length = 10)
private String timeframe;
/** 차트 타입 (candlestick/bar/line/area/baseline) */
@Column(name = "chart_type", length = 20)
@Builder.Default
private String chartType = "candlestick";
/** 테마 (dark/light/blue) */
@Column(name = "theme", length = 20)
@Builder.Default
private String theme = "dark";
/** 차트 모드 (chart/trading) */
@Column(name = "mode", length = 20)
@Builder.Default
private String mode = "chart";
/** 로그 스케일 사용 여부 */
@Column(name = "log_scale")
@Builder.Default
private Boolean logScale = false;
/**
* 지표 설정 JSON 배열.
* 형식: [{id, type, params, hidden, plotVisibility}]
* frontend IndicatorConfig[] 구조와 1:1 대응
*/
@Column(name = "indicators_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
private String indicatorsJson;
/**
* 드로잉 객체 JSON 배열.
* 형식: [{id, type, points, color, lineWidth, style, text, visible, fibtzSettings}]
* frontend Drawing[] 구조와 1:1 대응
*/
@Column(name = "drawings_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
private String drawingsJson;
/** 드로잉 잠금 여부 */
@Column(name = "drawings_locked")
@Builder.Default
private Boolean drawingsLocked = false;
/** 드로잉 표시 여부 */
@Column(name = "drawings_visible")
@Builder.Default
private Boolean drawingsVisible = true;
/**
* 보조지표 창(pane) 레이아웃 JSON.
* 형식: [{paneIndex, height}]
*/
@Column(name = "pane_layout_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
private String paneLayoutJson;
/**
* 메인 차트 캔들 색상 설정 JSON.
* frontend MainChartStyle 구조
*/
@Column(name = "main_chart_style_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
private String mainChartStyleJson;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,64 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* 사용자 차트 워크스페이스.
* 멀티차트 레이아웃 및 슬롯 집합을 관리한다.
*/
@Entity
@Table(name = "gc_chart_workspace")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcChartWorkspace {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/** 소유 사용자 ID (users.id 논리 참조) */
@Column(name = "user_id")
private Long userId;
/** 비회원 기기 식별자 */
@Column(name = "device_id", length = 100)
private String deviceId;
/** 현재 적용된 레이아웃 ID (frontend layoutTypes.ts 의 LayoutDef.id 와 일치: "1","2v","2h",...) */
@Column(name = "layout_id", length = 20, nullable = false)
private String layoutId;
/** 차트 슬롯 설정 목록 (1:N) */
@OneToMany(mappedBy = "workspace", cascade = CascadeType.ALL, orphanRemoval = true)
@OrderBy("slotIndex ASC")
@Builder.Default
private List<GcChartSlot> slots = new ArrayList<>();
/** 차트 간 동기화 옵션 JSON {"symbol":true,"timeframe":false,"crosshair":true} */
@Column(name = "sync_options_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
private String syncOptionsJson;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,53 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "gc_fcm_token")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class GcFcmToken {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id")
private Long userId;
@Column(name = "device_id", nullable = false, length = 64)
private String deviceId;
@Column(nullable = false, unique = true, length = 512)
private String token;
@Column(nullable = false)
@Builder.Default
private Boolean active = true;
@Column(name = "last_used_at")
private LocalDateTime lastUsedAt;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,66 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 보유종목.
*/
@Entity
@Table(name = "gc_holdings",
uniqueConstraints = @UniqueConstraint(name = "uk_holdings_user_symbol",
columnNames = {"user_id", "device_id", "symbol"}))
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcHoldings {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id")
private Long userId;
@Column(name = "device_id", length = 100)
private String deviceId;
@Column(name = "symbol", length = 50, nullable = false)
private String symbol;
@Column(name = "korean_name", length = 100)
private String koreanName;
@Column(name = "english_name", length = 100)
private String englishName;
/** 평균 매입가 */
@Column(name = "avg_price", precision = 30, scale = 8)
private BigDecimal avgPrice;
/** 보유 수량 */
@Column(name = "quantity", precision = 30, scale = 8)
private BigDecimal quantity;
@Column(name = "display_order")
@Builder.Default
private Integer displayOrder = 0;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,85 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
import java.time.LocalDateTime;
/**
* 장치/사용자별 전역 지표 파라미터 설정.
*
* params_json 구조 예시:
* {
* "RSI": {"length": 9, "src": "close"},
* "MACD": {"fastLength": 12, "slowLength": 26, "signalLength": 9, "src": "close"},
* "BollingerBands": {"length": 20, "mult": 2.0, "src": "close"},
* "Stochastic": {"kLength": 14, "smooth": 3, "dSmoothing": 3},
* "IchimokuCloud": {"conversionPeriods": 9, "basePeriods": 26,
* "laggingSpan2Periods": 52, "displacement": 26},
* ...
* }
*
* 프론트엔드 indicatorRegistry.ts 의 defaultParams 를 완전히 대체한다.
*/
@Entity
@Table(name = "gc_indicator_settings")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcIndicatorSettings {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/** 비회원 기기 식별자 (X-Device-Id 헤더) */
@Column(name = "device_id", length = 100, unique = true)
private String deviceId;
/** 회원 ID (향후 확장) */
@Column(name = "user_id", unique = true)
private Long userId;
/**
* 지표 타입 → 파라미터 맵의 JSON 직렬화.
* Map&lt;String, Map&lt;String, Object&gt;&gt; 형태로 역직렬화한다.
*/
@Column(name = "params_json", columnDefinition = "JSON", nullable = false)
@JdbcTypeCode(SqlTypes.JSON)
@Builder.Default
private String paramsJson = "{}";
/**
* 지표 타입 → 시각 설정(색상·선굵기·수평선) JSON 직렬화.
* Map&lt;String, IndicatorVisual&gt; 형태로 역직렬화한다.
* <pre>
* {
* "RSI": {
* "plots": [{"id":"plot0","color":"#7E57C2","lineWidth":2,"type":"line"}],
* "hlines": [{"price":70,"color":"#EF5350","visible":true}]
* }
* }
* </pre>
*/
@Column(name = "visual_config_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
@Builder.Default
private String visualConfigJson = "{}";
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,75 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
/**
* 디바이스/유저 × 마켓별 실시간 전략 체크 설정.
*
* <ul>
* <li>isLiveCheck — 실시간 체크 ON/OFF</li>
* <li>executionType — CANDLE_CLOSE | REALTIME_TICK</li>
* <li>strategyId — 연결된 gc_strategy.id (null 이면 체크 비활성)</li>
* </ul>
*/
@Entity
@Table(name = "gc_live_strategy_settings")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcLiveStrategySettings {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "device_id", length = 100)
private String deviceId;
@Column(name = "user_id")
private Long userId;
@Column(name = "market", nullable = false, length = 30)
@Builder.Default
private String market = "KRW-BTC";
/** 연결된 전략 ID (null = 미연결) */
@Column(name = "strategy_id")
private Long strategyId;
@Column(name = "is_live_check", nullable = false)
@Builder.Default
private Boolean isLiveCheck = false;
/** CANDLE_CLOSE | REALTIME_TICK */
@Column(name = "execution_type", nullable = false, length = 30)
@Builder.Default
private String executionType = "CANDLE_CLOSE";
/** 전략 평가·데이터 수집 분봉 (1m, 3m, 5m, …) */
@Column(name = "candle_type", nullable = false, length = 10)
@Builder.Default
private String candleType = "1m";
/** 매도 시그널 포지션 종속성 모드: LONG_ONLY | SIGNAL_ONLY */
@Column(name = "position_mode", nullable = false, length = 20)
@Builder.Default
private String positionMode = "LONG_ONLY";
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,67 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Entity
@Table(name = "gc_live_trade")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcLiveTrade {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "device_id", nullable = false, length = 100)
private String deviceId;
@Column(name = "user_id")
private Long userId;
@Column(name = "symbol", nullable = false, length = 30)
private String symbol;
@Column(name = "side", nullable = false, length = 8)
private String side;
@Column(name = "order_kind", nullable = false, length = 16)
@Builder.Default
private String orderKind = "market";
@Column(name = "source", nullable = false, length = 32)
@Builder.Default
private String source = "STRATEGY";
@Column(name = "strategy_id")
private Long strategyId;
@Column(name = "upbit_order_uuid", length = 64)
private String upbitOrderUuid;
@Column(name = "price", nullable = false, precision = 20, scale = 8)
private BigDecimal price;
@Column(name = "quantity", nullable = false, precision = 24, scale = 12)
private BigDecimal quantity;
@Column(name = "gross_amount", nullable = false, precision = 20, scale = 2)
private BigDecimal grossAmount;
@Column(name = "fee_amount", precision = 20, scale = 2)
private BigDecimal feeAmount;
@Column(name = "state", nullable = false, length = 24)
@Builder.Default
private String state = "done";
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@PrePersist
void onCreate() {
createdAt = LocalDateTime.now();
}
}
@@ -0,0 +1,48 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Entity
@Table(name = "gc_paper_account")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcPaperAccount {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id")
private Long userId;
@Column(name = "device_id", length = 100, nullable = false, unique = true)
private String deviceId;
@Column(name = "cash_balance", precision = 20, scale = 2, nullable = false)
@Builder.Default
private BigDecimal cashBalance = BigDecimal.valueOf(10_000_000);
@Column(name = "realized_pnl", precision = 20, scale = 2, nullable = false)
@Builder.Default
private BigDecimal realizedPnl = BigDecimal.ZERO;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,53 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Entity
@Table(name = "gc_paper_position",
uniqueConstraints = @UniqueConstraint(name = "uk_paper_position_account_symbol",
columnNames = {"account_id", "symbol"}))
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcPaperPosition {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "account_id", nullable = false)
private Long accountId;
@Column(name = "symbol", length = 50, nullable = false)
private String symbol;
@Column(name = "korean_name", length = 100)
private String koreanName;
@Column(name = "quantity", precision = 30, scale = 12, nullable = false)
@Builder.Default
private BigDecimal quantity = BigDecimal.ZERO;
@Column(name = "avg_price", precision = 20, scale = 2, nullable = false)
@Builder.Default
private BigDecimal avgPrice = BigDecimal.ZERO;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,64 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Entity
@Table(name = "gc_paper_trade")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcPaperTrade {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "account_id", nullable = false)
private Long accountId;
@Column(name = "symbol", length = 50, nullable = false)
private String symbol;
@Column(name = "side", length = 10, nullable = false)
private String side;
@Column(name = "order_kind", length = 20, nullable = false)
@Builder.Default
private String orderKind = "limit";
@Column(name = "source", length = 20, nullable = false)
@Builder.Default
private String source = "MANUAL";
@Column(name = "strategy_id")
private Long strategyId;
@Column(name = "price", precision = 20, scale = 2, nullable = false)
private BigDecimal price;
@Column(name = "quantity", precision = 30, scale = 12, nullable = false)
private BigDecimal quantity;
@Column(name = "gross_amount", precision = 20, scale = 2, nullable = false)
private BigDecimal grossAmount;
@Column(name = "fee_amount", precision = 20, scale = 2, nullable = false)
@Builder.Default
private BigDecimal feeAmount = BigDecimal.ZERO;
@Column(name = "net_amount", precision = 20, scale = 2, nullable = false)
private BigDecimal netAmount;
@Column(name = "cash_after", precision = 20, scale = 2, nullable = false)
private BigDecimal cashAfter;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
}
}
@@ -0,0 +1,24 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
@Entity
@Table(name = "gc_role_menu_permission",
uniqueConstraints = @UniqueConstraint(columnNames = {"role", "menu_id"}))
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcRoleMenuPermission {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 20)
private String role;
@Column(name = "menu_id", nullable = false, length = 50)
private String menuId;
@Column(nullable = false)
private Boolean allowed = true;
}
@@ -0,0 +1,67 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
import java.time.LocalDateTime;
/**
* GoldenChart 투자전략 DSL 엔티티.
* frontend StrategyPage 에서 작성한 LogicNode 트리를 JSON 으로 저장.
*/
@Entity
@Table(name = "gc_strategy")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcStrategy {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/** 로그인 사용자 ID (nullable — 비회원은 device_id 사용) */
@Column(name = "user_id")
private Long userId;
/** 비회원 기기 식별자 */
@Column(name = "device_id", length = 100)
private String deviceId;
@Column(name = "name", nullable = false, length = 200)
private String name;
@Column(name = "description", columnDefinition = "TEXT")
private String description;
/** 매수 조건 DSL JSON — frontend LogicNode 구조 */
@Column(name = "buy_condition_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
private String buyConditionJson;
/** 매도 조건 DSL JSON — frontend LogicNode 구조 */
@Column(name = "sell_condition_json", columnDefinition = "JSON")
@JdbcTypeCode(SqlTypes.JSON)
private String sellConditionJson;
@Column(name = "enabled", nullable = false)
@Builder.Default
private Boolean enabled = true;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,59 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
/**
* 실시간 전략 체크에서 발생한 매매 시그널 이력.
*/
@Entity
@Table(name = "gc_trade_signal")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcTradeSignal {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "device_id", length = 100)
private String deviceId;
@Column(name = "user_id")
private Long userId;
@Column(name = "market", nullable = false, length = 30)
private String market;
@Column(name = "strategy_id")
private Long strategyId;
@Column(name = "strategy_name", length = 200)
private String strategyName;
/** BUY | SELL */
@Column(name = "signal_type", nullable = false, length = 10)
private String signalType;
@Column(name = "price", nullable = false)
private Double price;
/** 캔들 시작 Unix 초 */
@Column(name = "candle_time", nullable = false)
private Long candleTime;
@Column(name = "candle_type", nullable = false, length = 10)
@Builder.Default
private String candleType = "1m";
/** CANDLE_CLOSE | REALTIME_TICK */
@Column(name = "execution_type", nullable = false, length = 30)
private String executionType;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@PrePersist
protected void onCreate() { createdAt = LocalDateTime.now(); }
}
@@ -0,0 +1,50 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "gc_user")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 50)
private String username;
@Column(name = "password_hash", nullable = false, length = 100)
private String passwordHash;
@Column(name = "display_name", length = 100)
private String displayName;
@Column(nullable = false)
private Boolean enabled = true;
/** ADMIN | USER | GUEST */
@Column(nullable = false, length = 20)
private String role = "USER";
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
void prePersist() {
LocalDateTime now = LocalDateTime.now();
if (createdAt == null) createdAt = now;
updatedAt = now;
}
@PreUpdate
void preUpdate() {
updatedAt = LocalDateTime.now();
}
}
@@ -0,0 +1,49 @@
package com.goldenchart.entity;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
/**
* 관심종목 (워치리스트).
* 기존 crypto_favorites 와 별도로 GoldenChart 전용 관리.
*/
@Entity
@Table(name = "gc_watchlist",
uniqueConstraints = @UniqueConstraint(name = "uk_watchlist_user_symbol",
columnNames = {"user_id", "device_id", "symbol"}))
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder
public class GcWatchlist {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id")
private Long userId;
@Column(name = "device_id", length = 100)
private String deviceId;
@Column(name = "symbol", length = 50, nullable = false)
private String symbol;
@Column(name = "korean_name", length = 100)
private String koreanName;
@Column(name = "english_name", length = 100)
private String englishName;
@Column(name = "display_order")
@Builder.Default
private Integer displayOrder = 0;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
}
}