From 4a37a5a53f8ed77a035186622499e7e0d50afde5 Mon Sep 17 00:00:00 2001 From: CircleSoar <493943239@qq.com> Date: Thu, 2 Apr 2026 21:39:12 +0800 Subject: [PATCH 1/2] Translate all Chinese UI text to English - Translate model display methods (Trader, TradingStrategy, FactorDefinition, TradingSignal) - Translate helper methods and controller flash messages - Translate all view templates (traders, assets, admin, allocations, etc.) - Translate JavaScript controller strings - Add Rake tasks for batch trader name updates Co-Authored-By: Claude Opus 4.6 --- .../admin/factor_definitions_controller.rb | 6 +- .../admin/signal_daily_reports_controller.rb | 16 +- app/controllers/ai_analysis_controller.rb | 8 +- .../allocation_decisions_controller.rb | 4 +- app/controllers/application_controller.rb | 2 +- .../trader_reflections_controller.rb | 8 +- app/controllers/traders_controller.rb | 6 +- app/helpers/application_helper.rb | 24 +- app/helpers/assets_helper.rb | 12 +- .../controllers/assets_controller.js | 8 +- .../controllers/recommendation_controller.js | 2 +- app/models/factor_definition.rb | 14 +- app/models/job_execution.rb | 14 +- app/models/trader.rb | 4 +- app/models/trading_signal.rb | 6 +- app/models/trading_strategy.rb | 58 ++--- app/views/admin/dashboard/index.html.erb | 40 +-- .../admin/factor_daily_reports/index.html.erb | 22 +- .../admin/factor_definitions/edit.html.erb | 36 +-- .../admin/factor_definitions/index.html.erb | 24 +- .../admin/factor_definitions/show.html.erb | 26 +- .../admin/signal_daily_reports/index.html.erb | 22 +- .../admin/trading_signals/index.html.erb | 58 ++--- app/views/admin/trading_signals/show.html.erb | 24 +- app/views/ai_analysis/show.html.erb | 2 +- app/views/allocation_decisions/index.html.erb | 28 +- app/views/allocation_decisions/show.html.erb | 68 ++--- app/views/allocation_previews/show.html.erb | 62 ++--- app/views/allocation_tasks/index.html.erb | 28 +- app/views/allocation_tasks/show.html.erb | 44 ++-- app/views/assets/analysis.html.erb | 100 ++++---- app/views/assets/index.html.erb | 48 ++-- app/views/assets/show.html.erb | 68 ++--- app/views/home/index.html.erb | 62 ++--- app/views/portfolio_dashboards/show.html.erb | 78 +++--- app/views/trader_reflections/show.html.erb | 102 ++++---- app/views/traders/_form.html.erb | 36 +-- app/views/traders/edit.html.erb | 8 +- app/views/traders/index.html.erb | 30 +-- app/views/traders/new.html.erb | 8 +- app/views/traders/show.html.erb | 120 ++++----- lib/tasks/trader_name_mapping.json | 44 ++++ lib/tasks/trader_name_mapping_example.json | 20 ++ lib/tasks/update_traders.rake | 242 ++++++++++++++++++ 44 files changed, 974 insertions(+), 668 deletions(-) create mode 100644 lib/tasks/trader_name_mapping.json create mode 100644 lib/tasks/trader_name_mapping_example.json create mode 100644 lib/tasks/update_traders.rake diff --git a/app/controllers/admin/factor_definitions_controller.rb b/app/controllers/admin/factor_definitions_controller.rb index 3bcea3c..6baa1d1 100644 --- a/app/controllers/admin/factor_definitions_controller.rb +++ b/app/controllers/admin/factor_definitions_controller.rb @@ -54,7 +54,7 @@ def edit; end def update if @factor.update(factor_params) - redirect_to admin_factor_definition_path(@factor), notice: "因子更新成功" + redirect_to admin_factor_definition_path(@factor), notice: "Factor updated successfully" else render :edit, status: :unprocessable_entity end @@ -62,8 +62,8 @@ def update def toggle @factor.update!(active: !@factor.active) - status_text = @factor.active? ? "启用" : "禁用" - redirect_to admin_factor_definitions_path, notice: "因子已#{status_text}" + status_text = @factor.active? ? "enabled" : "disabled" + redirect_to admin_factor_definitions_path, notice: "Factor #{status_text}" end private diff --git a/app/controllers/admin/signal_daily_reports_controller.rb b/app/controllers/admin/signal_daily_reports_controller.rb index e1db993..a973ee8 100644 --- a/app/controllers/admin/signal_daily_reports_controller.rb +++ b/app/controllers/admin/signal_daily_reports_controller.rb @@ -26,7 +26,7 @@ def create @report = DailyReport.new(report_params.merge(report_type: REPORT_TYPE)) if @report.save - redirect_to admin_signal_daily_report_path(@report), notice: '日报创建成功' + redirect_to admin_signal_daily_report_path(@report), notice: 'Daily report created successfully' else render :new, status: :unprocessable_entity end @@ -36,7 +36,7 @@ def edit; end def update if @report.update(report_params) - redirect_to admin_signal_daily_report_path(@report), notice: '日报更新成功' + redirect_to admin_signal_daily_report_path(@report), notice: 'Daily report updated successfully' else render :edit, status: :unprocessable_entity end @@ -44,7 +44,7 @@ def update def destroy @report.destroy - redirect_to admin_signal_daily_reports_path, notice: '日报已删除' + redirect_to admin_signal_daily_reports_path, notice: 'Daily report deleted' end def generate @@ -52,7 +52,7 @@ def generate existing = DailyReport.find_by(report_type: REPORT_TYPE, report_date: date) if existing - redirect_to admin_signal_daily_report_path(existing), alert: '该日期的日报已存在' + redirect_to admin_signal_daily_report_path(existing), alert: 'Daily report for this date already exists' return end @@ -60,9 +60,9 @@ def generate report = DailyReport.find_by(report_type: REPORT_TYPE, report_date: date) if report - redirect_to admin_signal_daily_report_path(report), notice: '日报生成成功' + redirect_to admin_signal_daily_report_path(report), notice: 'Daily report generated successfully' else - redirect_to admin_signal_daily_reports_path, alert: '日报生成失败' + redirect_to admin_signal_daily_reports_path, alert: 'Failed to generate daily report' end end @@ -72,9 +72,9 @@ def regenerate report = DailyReport.find_by(report_type: REPORT_TYPE, report_date: date) if report - redirect_to admin_signal_daily_report_path(report), notice: '日报重新生成成功' + redirect_to admin_signal_daily_report_path(report), notice: 'Daily report regenerated successfully' else - redirect_to admin_signal_daily_report_path(@report), alert: '日报重新生成失败' + redirect_to admin_signal_daily_report_path(report), alert: 'Failed to regenerate daily report' end end diff --git a/app/controllers/ai_analysis_controller.rb b/app/controllers/ai_analysis_controller.rb index 7ea79d5..4088961 100644 --- a/app/controllers/ai_analysis_controller.rb +++ b/app/controllers/ai_analysis_controller.rb @@ -15,18 +15,18 @@ def create @assets = @assets_input.split(/[,\s]+/).map(&:strip).map(&:upcase).reject(&:empty?) if @assets.empty? - flash[:alert] = "请至少输入一个资产" + flash[:alert] = "Please enter at least one asset" redirect_to new_ai_analysis_path and return end - # 执行分析(不再依赖 Trader) + # Execute analysis (no longer depends on Trader) @result = perform_analysis(@assets, @analysis_type) - # 将结果存入 Rails.cache 供 show 页面使用 + # Store result in Rails.cache for show page result_cache_key = "ai_analysis_result_#{Time.current.to_i}" Rails.cache.write(result_cache_key, @result, expires_in: 10.minutes) - flash[:notice] = "分析完成!共分析 #{@assets.length} 个资产" + flash[:notice] = "Analysis completed! Analyzed #{@assets.length} assets" redirect_to ai_analysis_result_path(result_key: result_cache_key, assets: @assets.join(",")) end diff --git a/app/controllers/allocation_decisions_controller.rb b/app/controllers/allocation_decisions_controller.rb index f1b5efe..bf43742 100644 --- a/app/controllers/allocation_decisions_controller.rb +++ b/app/controllers/allocation_decisions_controller.rb @@ -17,9 +17,9 @@ def show def execute AllocationExecutionService.new(@allocation_decision).call - redirect_to allocation_decision_path(@allocation_decision), notice: "配置建议已执行" + redirect_to allocation_decision_path(@allocation_decision), notice: "Allocation recommendation executed" rescue StandardError => e - redirect_to allocation_decision_path(@allocation_decision), alert: "执行失败: #{e.message}" + redirect_to allocation_decision_path(@allocation_decision), alert: "Execution failed: #{e.message}" end private diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5614c60..cd840f0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,6 +14,6 @@ def current_user end def require_user - redirect_to login_path, alert: "请先登录" unless current_user + redirect_to login_path, alert: "Please log in first" unless current_user end end diff --git a/app/controllers/trader_reflections_controller.rb b/app/controllers/trader_reflections_controller.rb index dccaf8c..0e77319 100644 --- a/app/controllers/trader_reflections_controller.rb +++ b/app/controllers/trader_reflections_controller.rb @@ -7,9 +7,9 @@ class TraderReflectionsController < ApplicationController def create reflection = TraderReflectionService.new(@trader).call - redirect_to trader_trader_reflection_path(@trader, reflection), notice: "反思报告生成成功" + redirect_to trader_trader_reflection_path(@trader, reflection), notice: "Reflection report generated successfully" rescue StandardError => e - redirect_to trader_path(@trader), alert: "反思报告生成失败:#{e.message}" + redirect_to trader_path(@trader), alert: "Failed to generate reflection report: #{e.message}" end def show; end @@ -20,9 +20,9 @@ def apply_adjustment parameter: params[:parameter] ).call - redirect_to trader_trader_reflection_path(@trader, @trader_reflection), notice: "策略参数已应用到当前策略" + redirect_to trader_trader_reflection_path(@trader, @trader_reflection), notice: "Strategy parameters applied to current strategy" rescue StandardError => e - redirect_to trader_trader_reflection_path(@trader, @trader_reflection), alert: "应用建议失败:#{e.message}" + redirect_to trader_trader_reflection_path(@trader, @trader_reflection), alert: "Failed to apply suggestion: #{e.message}" end private diff --git a/app/controllers/traders_controller.rb b/app/controllers/traders_controller.rb index 2250cdd..f757df1 100644 --- a/app/controllers/traders_controller.rb +++ b/app/controllers/traders_controller.rb @@ -30,7 +30,7 @@ def create if @trader.save generate_strategies_for(@trader) - redirect_to @trader, notice: "操盘手创建成功" + redirect_to @trader, notice: "Trader created successfully" else render :new, status: :unprocessable_entity end @@ -39,7 +39,7 @@ def create def update if @trader.update(trader_params) regenerate_strategies_if_needed(@trader) - redirect_to @trader, notice: "操盘手更新成功" + redirect_to @trader, notice: "Trader updated successfully" else render :edit, status: :unprocessable_entity end @@ -47,7 +47,7 @@ def update def destroy @trader.destroy - redirect_to traders_url, notice: "操盘手已删除" + redirect_to traders_url, notice: "Trader deleted" end private diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index d578bc2..624de1d 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,16 +1,16 @@ module ApplicationHelper - # 渲染 Markdown 内容 + # Render Markdown content def render_markdown(text) return '' if text.nil? require 'kramdown' Kramdown::Document.new(text).to_html.html_safe rescue LoadError - # 如果 kramdown 不可用,使用简单的格式化 + # Use simple formatting if kramdown is not available simple_format(text) end - # 根据资产类型返回对应的样式类 + # Return style class based on asset type def asset_type_badge(type) case type.to_s.downcase when 'crypto' @@ -26,19 +26,19 @@ def asset_type_badge(type) end end - # 根据涨跌幅返回颜色类 + # Return color class based on price change def change_color_class(value) value.to_f >= 0 ? 'text-green-600' : 'text-red-600' end - # 格式化涨跌幅百分比 + # Format percentage change def format_change_percent(value) return '-' unless value.present? sign = value.to_f >= 0 ? '+' : '' "#{sign}#{value.to_f.round(2)}%" end - # Job 执行状态样式类 + # Job execution status style class def status_badge_class(status) case status.to_s.downcase when 'success' @@ -52,7 +52,7 @@ def status_badge_class(status) end end - # 格式化统计值 + # Format statistical value def format_stat_value(value) case value when Hash @@ -60,21 +60,21 @@ def format_stat_value(value) when Array value.join(', ') when TrueClass, FalseClass - value ? '是' : '否' + value ? 'Yes' : 'No' else value.to_s end end - # Job 执行状态标签 + # Job execution status label def status_label(status) case status.to_s.downcase when 'success' - '成功' + 'Success' when 'failed' - '失败' + 'Failed' when 'running' - '运行中' + 'Running' else status end diff --git a/app/helpers/assets_helper.rb b/app/helpers/assets_helper.rb index be6fe8a..26c48a4 100644 --- a/app/helpers/assets_helper.rb +++ b/app/helpers/assets_helper.rb @@ -34,12 +34,12 @@ def format_change_percent(change) # Returns human-readable label for timeframe def timeframe_label(tf) labels = { - "all" => "全部", - "1h" => "1小时", - "6h" => "6小时", - "24h" => "24小时", - "7d" => "7天", - "30d" => "30天" + "all" => "All", + "1h" => "1h", + "6h" => "6h", + "24h" => "24h", + "7d" => "7d", + "30d" => "30d" } labels[tf] || tf end diff --git a/app/javascript/controllers/assets_controller.js b/app/javascript/controllers/assets_controller.js index fa37dc0..fb510b4 100644 --- a/app/javascript/controllers/assets_controller.js +++ b/app/javascript/controllers/assets_controller.js @@ -193,11 +193,11 @@ export default class extends Controller { // Format trend direction formatTrend(trend) { const trends = { - bullish: "看涨 ↗", - bearish: "看跌 ↘", - neutral: "中性 →" + bullish: "Bullish ↗", + bearish: "Bearish ↘", + neutral: "Neutral →" } - return trends[trend] || "未知" + return trends[trend] || "Unknown" } // Get trend color class diff --git a/app/javascript/controllers/recommendation_controller.js b/app/javascript/controllers/recommendation_controller.js index 6b9517e..88c36a4 100644 --- a/app/javascript/controllers/recommendation_controller.js +++ b/app/javascript/controllers/recommendation_controller.js @@ -36,7 +36,7 @@ export default class extends Controller { const statusCell = row.querySelector("td:last-child") if (statusCell) { if (isSelected) { - statusCell.innerHTML = '已选择' + statusCell.innerHTML = 'Selected' } else { statusCell.innerHTML = "" } diff --git a/app/models/factor_definition.rb b/app/models/factor_definition.rb index 89a0357..7636e4a 100644 --- a/app/models/factor_definition.rb +++ b/app/models/factor_definition.rb @@ -7,12 +7,12 @@ class FactorDefinition < ApplicationRecord # Categories CATEGORIES = { - 'technical' => '技术因子', - 'fundamental' => '基本面因子', - 'sentiment' => '情绪因子', - 'momentum' => '动量因子', - 'risk' => '风险因子', - 'volume' => '成交量因子' + 'technical' => 'Technical Factor', + 'fundamental' => 'Fundamental Factor', + 'sentiment' => 'Sentiment Factor', + 'momentum' => 'Momentum Factor', + 'risk' => 'Risk Factor', + 'volume' => 'Volume Factor' }.freeze # Validations @@ -45,7 +45,7 @@ def display_weight end def display_status - active? ? '启用' : '禁用' + active? ? 'Active' : 'Inactive' end def parameter(key) diff --git a/app/models/job_execution.rb b/app/models/job_execution.rb index 6881fc8..15eaf9b 100644 --- a/app/models/job_execution.rb +++ b/app/models/job_execution.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class JobExecution < ApplicationRecord - # 状态常量 + # Status constants STATUS_RUNNING = "running" STATUS_SUCCESS = "success" STATUS_FAILED = "failed" @@ -11,7 +11,7 @@ class JobExecution < ApplicationRecord validates :status, presence: true, inclusion: { in: [ STATUS_RUNNING, STATUS_SUCCESS, STATUS_FAILED ] } validates :started_at, presence: true - # 作用域 + # Scopes scope :by_job_name, ->(name) { where(job_name: name) if name.present? } scope :by_status, ->(status) { where(status: status) if status.present? } scope :recent_first, -> { order(started_at: :desc) } @@ -19,13 +19,13 @@ class JobExecution < ApplicationRecord where(started_at: start_date..end_date) if start_date.present? && end_date.present? } - # 计算执行时长(秒) + # Calculate duration in seconds def duration_seconds return nil unless duration_ms (duration_ms / 1000.0).round(2) end - # 格式化执行时长 + # Format duration for display def formatted_duration return "-" unless duration_ms @@ -40,7 +40,7 @@ def formatted_duration end end - # 格式化参数显示 + # Format arguments for display def formatted_arguments return "-" unless arguments.present? @@ -54,7 +54,7 @@ def formatted_arguments end end - # 标记为成功 + # Mark as success def mark_success! now = Time.current update!( @@ -64,7 +64,7 @@ def mark_success! ) end - # 标记为失败 + # Mark as failed def mark_failed!(error_message) now = Time.current update!( diff --git a/app/models/trader.rb b/app/models/trader.rb index bd16034..6d4a610 100644 --- a/app/models/trader.rb +++ b/app/models/trader.rb @@ -48,11 +48,11 @@ def profit_loss_percent end def display_status - active? ? "启用" : "停用" + active? ? "Active" : "Inactive" end def display_risk_level - { "conservative" => "保守", "balanced" => "平衡", "aggressive" => "激进" }[risk_level] + { "conservative" => "Conservative", "balanced" => "Balanced", "aggressive" => "Aggressive" }[risk_level] end # Get strategy for a specific market condition diff --git a/app/models/trading_signal.rb b/app/models/trading_signal.rb index dbd533d..ef0aba8 100644 --- a/app/models/trading_signal.rb +++ b/app/models/trading_signal.rb @@ -53,9 +53,9 @@ def confidence_level def signal_type_label { - "buy" => "买入", - "sell" => "卖出", - "hold" => "持有" + "buy" => "Buy", + "sell" => "Sell", + "hold" => "Hold" }[signal_type] || signal_type end end diff --git a/app/models/trading_strategy.rb b/app/models/trading_strategy.rb index 5f7a593..c7f1d0a 100644 --- a/app/models/trading_strategy.rb +++ b/app/models/trading_strategy.rb @@ -28,91 +28,91 @@ class TradingStrategy < ApplicationRecord STRATEGY_MATRIX = { # Normal market conservative_normal: { - name: "稳健配置策略", + name: "Stable Allocation Strategy", max_positions: 2, buy_signal_threshold: 0.60, max_position_size: 0.40, min_cash_reserve: 0.30, - description: "注重本金保护,持仓集中,严格筛选买入信号,保留充足现金" + description: "Focus on capital preservation, concentrated holdings, strict buy signal filtering, maintain ample cash reserves" }, balanced_normal: { - name: "均衡配置策略", + name: "Balanced Allocation Strategy", max_positions: 3, buy_signal_threshold: 0.50, max_position_size: 0.50, min_cash_reserve: 0.20, - description: "平衡风险与收益,适度分散持仓,灵活调整仓位" + description: "Balance risk and return, moderately diversified holdings, flexible position adjustments" }, aggressive_normal: { - name: "积极成长策略", + name: "Growth Strategy", max_positions: 4, buy_signal_threshold: 0.40, max_position_size: 0.60, min_cash_reserve: 0.10, - description: "追求高收益,分散持仓,积极捕捉机会,保持高仓位运作" + description: "Pursue high returns, diversified holdings, actively capture opportunities, maintain high position levels" }, # Volatile market conservative_volatile: { - name: "减仓观望策略", + name: "Wait and See Strategy", max_positions: 2, buy_signal_threshold: 0.65, max_position_size: 0.30, min_cash_reserve: 0.40, - description: "高波动期减少持仓,提高买入门槛,保留更多现金等待机会" + description: "Reduce holdings during high volatility, raise buy threshold, preserve more cash for opportunities" }, balanced_volatile: { - name: "适度防御策略", + name: "Moderate Defense Strategy", max_positions: 3, buy_signal_threshold: 0.55, max_position_size: 0.40, min_cash_reserve: 0.30, - description: "适度降低仓位,提高选股标准,保持防御姿态" + description: "Moderately reduce positions, raise selection standards, maintain defensive posture" }, aggressive_volatile: { - name: "波段操作策略", + name: "Swing Trading Strategy", max_positions: 4, buy_signal_threshold: 0.45, max_position_size: 0.50, min_cash_reserve: 0.20, - description: "利用波动进行波段操作,快进快出,灵活应对" + description: "Utilize volatility for swing trading, quick entry and exit, flexible response" }, # Crash market conservative_crash: { - name: "防守保本策略", + name: "Capital Preservation Strategy", max_positions: 2, buy_signal_threshold: 0.70, max_position_size: 0.25, min_cash_reserve: 0.50, - description: "崩盘时期以保本为主,极低仓位,等待市场企稳" + description: "Prioritize capital preservation during market crash, very low positions, wait for market stabilization" }, balanced_crash: { - name: "小幅抄底策略", + name: "Moderate Dip Buying Strategy", max_positions: 3, buy_signal_threshold: 0.50, max_position_size: 0.40, min_cash_reserve: 0.30, - description: "适度参与抄底,分批建仓,控制风险敞口" + description: "Moderately participate in dip buying, build positions in batches, control risk exposure" }, aggressive_crash: { - name: "逆向买入策略", + name: "Contrarian Buying Strategy", max_positions: 5, buy_signal_threshold: 0.35, max_position_size: 0.65, min_cash_reserve: 0.05, - description: "逆向投资,在恐慌中积极买入优质资产,追求超额收益" + description: "Contrarian investment, actively buy quality assets during panic, pursue excess returns" }, # Bubble market conservative_bubble: { - name: "获利了结策略", + name: "Profit Taking Strategy", max_positions: 2, buy_signal_threshold: 0.70, max_position_size: 0.30, min_cash_reserve: 0.45, - description: "泡沫期逐步获利了结,降低仓位,锁定收益" + description: "Gradually take profits during bubble phase, reduce positions, lock in gains" }, balanced_bubble: { - name: "逐步减仓策略", + name: "Gradual Position Reduction Strategy", max_positions: 3, buy_signal_threshold: 0.60, max_position_size: 0.40, min_cash_reserve: 0.35, - description: "逐步降低仓位,提高现金比例,防范回调风险" + description: "Gradually reduce positions, increase cash ratio, guard against pullback risk" }, aggressive_bubble: { - name: "趋势跟随策略", + name: "Trend Following Strategy", max_positions: 4, buy_signal_threshold: 0.40, max_position_size: 0.55, min_cash_reserve: 0.15, - description: "顺势而为,跟随趋势但设置严格止损,及时止盈" + description: "Follow the trend, set strict stop-loss, take profits timely" } }.freeze # Market condition display names MARKET_CONDITION_DISPLAY = { - "normal" => "正常市场", - "volatile" => "高波动市场", - "crash" => "崩盘市场", - "bubble" => "泡沫市场" + "normal" => "Normal Market", + "volatile" => "Volatile Market", + "crash" => "Crash Market", + "bubble" => "Bubble Market" }.freeze # Class methods @@ -146,6 +146,6 @@ def display_market_condition end def display_generated_by - { "llm" => "AI 生成", "manual" => "手动配置", "default_template" => "默认模板", "matrix" => "矩阵策略" }[generated_by] + { "llm" => "AI Generated", "manual" => "Manual", "default_template" => "Default Template", "matrix" => "Matrix Strategy" }[generated_by] end end diff --git a/app/views/admin/dashboard/index.html.erb b/app/views/admin/dashboard/index.html.erb index e93a859..2c9c1e1 100644 --- a/app/views/admin/dashboard/index.html.erb +++ b/app/views/admin/dashboard/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "Admin 管理面板" %> +<% content_for :title, "Admin Dashboard" %>
@@ -17,8 +17,8 @@ <% end %>
-

Admin 管理面板

-

系统管理入口

+

Admin Dashboard

+

System Management Portal

@@ -35,7 +35,7 @@
<%= @factor_count %> - 活跃因子 + Active Factors
@@ -46,7 +46,7 @@
<%= @signal_count %> - 交易信号 + Trading Signals
@@ -59,7 +59,7 @@
<%= @job_stats[:failed] %> - 失败 Job + Failed Jobs
@@ -71,7 +71,7 @@
<%= @job_stats[:total] %> - 总 Job 数 + Total Jobs
@@ -88,8 +88,8 @@
-

因子定义

-

管理交易因子,定义因子参数和权重

+

Factor Definitions

+

Manage trading factors, define parameters and weights

@@ -106,8 +106,8 @@
-

交易信号

-

查看 AI 生成的交易信号

+

Trading Signals

+

View AI-generated trading signals

@@ -125,8 +125,8 @@
-

Job 监控

-

查看后台任务执行记录

+

Job Monitor

+

View background task execution records

@@ -145,8 +145,8 @@
-

Sidekiq 监控

-

Sidekiq 队列管理界面

+

Sidekiq Monitor

+

Sidekiq queue management interface

@@ -159,15 +159,15 @@
-

最近执行

+

Recent Executions

- - - - + + + + diff --git a/app/views/admin/factor_daily_reports/index.html.erb b/app/views/admin/factor_daily_reports/index.html.erb index a70074b..f9df137 100644 --- a/app/views/admin/factor_daily_reports/index.html.erb +++ b/app/views/admin/factor_daily_reports/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "因子日报列表 - SmartTrader" %> +<% content_for :title, "Factor Daily Reports - SmartTrader" %>
@@ -9,14 +9,14 @@ - 返回因子管理 + Back to Factor Management <% end %> -

因子日报

+

Factor Daily Reports

<%= form_with url: generate_admin_factor_daily_reports_path, method: :post, local: true, class: "reports-generate-form" do |f| %> <%= date_field_tag :date, Date.current, class: "date-input" %> - <%= submit_tag "手动生成", class: "btn btn-primary" %> + <%= submit_tag "Generate", class: "btn btn-primary" %> <% end %>
@@ -40,7 +40,7 @@ <% @reports.each do |report| %>
- <%= report.report_date.strftime('%Y年%m月%d日') %> + <%= report.report_date.strftime('%Y-%m-%d') %>
<%= truncate(report.summary, length: 100) %> @@ -53,13 +53,13 @@ <%= report.published_label %>
- <%= link_to admin_factor_daily_report_path(report), class: "btn btn-sm", title: "查看详情" do %> + <%= link_to admin_factor_daily_report_path(report), class: "btn btn-sm", title: "View Details" do %> <% end %> - <%= link_to edit_admin_factor_daily_report_path(report), class: "btn btn-sm btn-secondary", title: "编辑" do %> + <%= link_to edit_admin_factor_daily_report_path(report), class: "btn btn-sm btn-secondary", title: "Edit" do %> @@ -68,8 +68,8 @@ <%= button_to admin_factor_daily_report_path(report), method: :delete, class: "btn btn-sm btn-danger", - title: "删除", - data: { turbo_confirm: "确定要删除此日报吗?" } do %> + title: "Delete", + data: { turbo_confirm: "Are you sure you want to delete this report?" } do %> @@ -86,8 +86,8 @@ -

暂无日报记录

-

点击上方"手动生成"按钮创建第一份日报

+

No daily reports yet

+

Click the "Generate" button above to create the first report

<% end %>
diff --git a/app/views/admin/factor_definitions/edit.html.erb b/app/views/admin/factor_definitions/edit.html.erb index 44daea6..4671f01 100644 --- a/app/views/admin/factor_definitions/edit.html.erb +++ b/app/views/admin/factor_definitions/edit.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "编辑 #{@factor.name} - SmartTrader" %> +<% content_for :title, "Edit #{@factor.name} - SmartTrader" %>
@@ -8,11 +8,11 @@ - 返回详情 + Back to Details <% end %>
-

编辑因子

+

Edit Factor

@@ -33,31 +33,31 @@
-

基本信息

+

Basic Information

- <%= f.label :name, "因子名称", class: "form-label" %> + <%= f.label :name, "Factor Name", class: "form-label" %> <%= f.text_field :name, class: "form-input" %>
- <%= f.label :description, "因子描述", class: "form-label" %> + <%= f.label :description, "Factor Description", class: "form-label" %> <%= f.text_area :description, rows: 4, class: "form-textarea" %>
- <%= f.label :category, "分类", class: "form-label" %> + <%= f.label :category, "Category", class: "form-label" %> <%= f.select :category, FactorDefinition.categories_for_select, {}, class: "form-select" %>
- <%= f.label :active, "状态", class: "form-label" %> + <%= f.label :active, "Status", class: "form-label" %>
@@ -66,39 +66,39 @@
-

参数配置

+

Parameter Configuration

- <%= f.label :weight, "默认权重", class: "form-label" %> + <%= f.label :weight, "Default Weight", class: "form-label" %>
<%= f.number_field :weight, step: 0.01, min: 0, max: 1, class: "form-input" %> %
-

权重范围: 0 - 1 (如 0.20 表示 20%)

+

Weight range: 0 - 1 (e.g., 0.20 for 20%)

- <%= f.label :update_frequency, "更新频率", class: "form-label" %> + <%= f.label :update_frequency, "Update Frequency", class: "form-label" %>
<%= f.number_field :update_frequency, min: 1, class: "form-input" %> - 分钟 + minutes
- <%= f.label :parameters, "计算参数 (JSON)", class: "form-label" %> + <%= f.label :parameters, "Calculation Parameters (JSON)", class: "form-label" %> <%= f.text_area :parameters, value: @factor.parameters.to_json, rows: 3, class: "form-textarea font-mono" %> -

例如: {"days": 20, "threshold": 1.5}

+

Example: {"days": 20, "threshold": 1.5}

- <%= link_to "取消", admin_factor_definition_path(@factor), class: "btn btn-ghost" %> - <%= f.submit "保存更改", class: "btn btn-primary" %> + <%= link_to "Cancel", admin_factor_definition_path(@factor), class: "btn btn-ghost" %> + <%= f.submit "Save Changes", class: "btn btn-primary" %>
<% end %> diff --git a/app/views/admin/factor_definitions/index.html.erb b/app/views/admin/factor_definitions/index.html.erb index 764014f..a0c0ad9 100644 --- a/app/views/admin/factor_definitions/index.html.erb +++ b/app/views/admin/factor_definitions/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "因子管理 - SmartTrader" %> +<% content_for :title, "Factor Management - SmartTrader" %>
@@ -16,16 +16,16 @@ <% end %> -

因子管理

+

Factor Management

- 共 <%= @factors.count %> 个因子 · 总权重 <%= (@factors.sum(:weight) * 100).round(0) %>% + <%= @factors.count %> factors · Total weight <%= (@factors.sum(:weight) * 100).round(0) %>%
<%= link_to admin_factor_daily_reports_path, class: "factors-header__report-btn", - title: "查看因子日报列表" do %> + title: "View factor daily reports" do %> @@ -33,7 +33,7 @@ - 因子日报<% if @latest_report %> <%= @latest_report.report_date.strftime('%m/%d') %><% end %> + Factor Reports<% if @latest_report %> <%= @latest_report.report_date.strftime('%m/%d') %><% end %> <% end %> <%= link_to matrix_admin_factor_definitions_path, class: "factors-header__matrix-btn" do %> @@ -42,7 +42,7 @@ - 因子矩阵 + Factor Matrix <% end %> <%= link_to correlations_admin_factor_definitions_path, class: "factors-header__matrix-btn" do %> @@ -50,7 +50,7 @@ - 相关性 + Correlations <% end %>
@@ -126,18 +126,18 @@
- 权重 + Weight <%= factor.display_weight %>
- 周期 - <%= factor.calculation_days %>日 + Period + <%= factor.calculation_days %>d
- <%= link_to "详情", admin_factor_definition_path(factor), class: "btn btn-secondary btn-sm" %> - <%= button_to factor.active? ? "禁用" : "启用", + <%= link_to "Details", admin_factor_definition_path(factor), class: "btn btn-secondary btn-sm" %> + <%= button_to factor.active? ? "Disable" : "Enable", toggle_admin_factor_definition_path(factor), method: :post, class: factor.active? ? "btn btn-danger btn-sm" : "btn btn-primary btn-sm" %> diff --git a/app/views/admin/factor_definitions/show.html.erb b/app/views/admin/factor_definitions/show.html.erb index 0c298f6..a4cb485 100644 --- a/app/views/admin/factor_definitions/show.html.erb +++ b/app/views/admin/factor_definitions/show.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "#{@factor.name} - 因子详情 - SmartTrader" %> +<% content_for :title, "#{@factor.name} - Factor Details - SmartTrader" %>
@@ -8,11 +8,11 @@ - 返回列表 + Back to List <% end %>
- <%= link_to "编辑因子", edit_admin_factor_definition_path(@factor), class: "btn btn-primary" %> + <%= link_to "Edit Factor", edit_admin_factor_definition_path(@factor), class: "btn btn-primary" %>
@@ -78,25 +78,25 @@
- 分类 + Category <%= @factor.display_category %>
- 默认权重 + Default Weight <%= @factor.display_weight %>
- 更新频率 - 每 <%= @factor.update_frequency %> 分钟 + Update Frequency + Every <%= @factor.update_frequency %> minutes
- 计算方法 + Calculation Method <%= @factor.calculation_method %>
-

因子描述

+

Factor Description

<%= @factor.description %>

@@ -105,7 +105,7 @@
-

参数配置

+

Parameter Configuration

@@ -119,7 +119,7 @@ <% end %>
<% else %> -

暂无参数配置

+

No parameter configuration

<% end %>
@@ -127,7 +127,7 @@
-

计算说明

+

Calculation Description

@@ -137,7 +137,7 @@ <%= simple_format(@factor.formula, class: "factor-formula__text") %>
<% else %> -

暂无计算说明

+

No calculation description

<% end %>
diff --git a/app/views/admin/signal_daily_reports/index.html.erb b/app/views/admin/signal_daily_reports/index.html.erb index 685f833..1e53ef4 100644 --- a/app/views/admin/signal_daily_reports/index.html.erb +++ b/app/views/admin/signal_daily_reports/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "信号日报列表 - SmartTrader" %> +<% content_for :title, "Signal Daily Reports - SmartTrader" %>
@@ -9,14 +9,14 @@ - 返回信号管理 + Back to Signal Management <% end %> -

信号日报

+

Signal Daily Reports

<%= form_with url: generate_admin_signal_daily_reports_path, method: :post, local: true, class: "reports-generate-form" do |f| %> <%= date_field_tag :date, Date.current, class: "date-input" %> - <%= submit_tag "手动生成", class: "btn btn-primary" %> + <%= submit_tag "Generate", class: "btn btn-primary" %> <% end %>
@@ -40,7 +40,7 @@ <% @reports.each do |report| %>
- <%= report.report_date.strftime('%Y年%m月%d日') %> + <%= report.report_date.strftime('%Y-%m-%d') %>
<%= truncate(report.summary, length: 100) %> @@ -53,13 +53,13 @@ <%= report.published_label %>
- <%= link_to admin_signal_daily_report_path(report), class: "btn btn-sm", title: "查看详情" do %> + <%= link_to admin_signal_daily_report_path(report), class: "btn btn-sm", title: "View Details" do %> <% end %> - <%= link_to edit_admin_signal_daily_report_path(report), class: "btn btn-sm btn-secondary", title: "编辑" do %> + <%= link_to edit_admin_signal_daily_report_path(report), class: "btn btn-sm btn-secondary", title: "Edit" do %> @@ -68,8 +68,8 @@ <%= button_to admin_signal_daily_report_path(report), method: :delete, class: "btn btn-sm btn-danger", - title: "删除", - data: { turbo_confirm: "确定要删除此日报吗?" } do %> + title: "Delete", + data: { turbo_confirm: "Are you sure you want to delete this report?" } do %> @@ -84,8 +84,8 @@ -

暂无日报记录

-

点击上方"手动生成"按钮创建第一份日报

+

No daily reports yet

+

Click the "Generate" button above to create the first report

<% end %>
diff --git a/app/views/admin/trading_signals/index.html.erb b/app/views/admin/trading_signals/index.html.erb index abd62d0..0b3e751 100644 --- a/app/views/admin/trading_signals/index.html.erb +++ b/app/views/admin/trading_signals/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "交易信号" %> +<% content_for :title, "Trading Signals" %>
@@ -16,8 +16,8 @@ <% end %>
-

交易信号

-

AI 生成的交易信号列表

+

Trading Signals

+

AI-Generated Trading Signals List

@@ -28,11 +28,11 @@ - 因子管理 + Factor Management <% end %> <%= link_to admin_signal_daily_reports_path, class: "signals-btn signals-btn--secondary", - title: "查看信号日报列表" do %> + title: "View signal daily reports list" do %> @@ -40,7 +40,7 @@ - 信号日报<% if @latest_report %> <%= @latest_report.report_date.strftime('%m/%d') %><% end %> + Signal Reports<% if @latest_report %> <%= @latest_report.report_date.strftime('%m/%d') %><% end %> <% end %> <%= link_to admin_job_executions_path, class: "signals-btn signals-btn--secondary" do %> @@ -48,13 +48,13 @@ - Job 监控 + Job Monitor <% end %> - <%= button_to generate_all_admin_trading_signals_path, method: :post, class: "signals-btn signals-btn--primary", data: { turbo_confirm: "确定要为所有资产生成信号吗?" } do %> + <%= button_to generate_all_admin_trading_signals_path, method: :post, class: "signals-btn signals-btn--primary", data: { turbo_confirm: "Are you sure you want to generate signals for all assets?" } do %> - 生成全部信号 + Generate All Signals <% end %>
@@ -69,7 +69,7 @@
<%= @stats[:total] %> - 总信号数 + Total Signals
@@ -81,7 +81,7 @@
<%= @stats[:buy] %> - 买入信号 + Buy Signals
@@ -93,7 +93,7 @@
<%= @stats[:sell] %> - 卖出信号 + Sell Signals
@@ -106,7 +106,7 @@
<%= @stats[:high_confidence] %> - 高置信度 + High Confidence
@@ -115,12 +115,12 @@
<%= form_with url: admin_trading_signals_path, method: :get, local: true, class: "signals-filters__form" do |f| %>
- - <%= f.select :signal_type, options_for_select([["全部", ""], ["买入", "buy"], ["卖出", "sell"], ["持有", "hold"]], params[:signal_type]), {}, class: "filter-select" %> + + <%= f.select :signal_type, options_for_select([["All", ""], ["Buy", "buy"], ["Sell", "sell"], ["Hold", "hold"]], params[:signal_type]), {}, class: "filter-select" %>
- <%= f.submit "筛选", class: "signals-btn signals-btn--small" %> - <%= link_to "重置", admin_trading_signals_path, class: "signals-btn signals-btn--small signals-btn--outline" %> + <%= f.submit "Filter", class: "signals-btn signals-btn--small" %> + <%= link_to "Reset", admin_trading_signals_path, class: "signals-btn signals-btn--small signals-btn--outline" %>
<% end %>
@@ -128,7 +128,7 @@ <% if @latest_signals.any? %>
-

最新信号概览

+

Latest Signals Overview

<% @latest_signals.each do |signal| %>
@@ -146,8 +146,8 @@

<%= truncate(signal.reasoning, length: 60) %>

<% end %> @@ -157,18 +157,18 @@
-

全部信号记录

+

All Signal Records

Job 名称状态开始时间耗时Job NameStatusStart TimeDuration
- - - - - - - + + + + + + + @@ -207,7 +207,7 @@ <%= signal.generated_at.strftime("%m-%d %H:%M") %> <% end %> diff --git a/app/views/admin/trading_signals/show.html.erb b/app/views/admin/trading_signals/show.html.erb index ee842d9..fbea60f 100644 --- a/app/views/admin/trading_signals/show.html.erb +++ b/app/views/admin/trading_signals/show.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "信号详情 - #{@signal.asset.symbol}" %> +<% content_for :title, "Signal Details - #{@signal.asset.symbol}" %>
@@ -15,7 +15,7 @@ - 返回信号列表 + Back to Signals <% end %>
@@ -77,7 +77,7 @@ %
-
置信度
+
Confidence
@@ -90,7 +90,7 @@ -

信号解读

+

Signal Interpretation

<%= @signal.reasoning %>

@@ -106,7 +106,7 @@
-

关键驱动因子

+

Key Driving Factors

@@ -135,7 +135,7 @@
-

风险提示

+

Risk Warning

<%= @signal.risk_warning %>

@@ -155,8 +155,8 @@
-

因子快照

- 生成时刻数据 +

Factor Snapshot

+ Data at Generation Time
@@ -164,7 +164,7 @@
<%= data["name"] %> - 权重 <%= (data["weight"].to_f * 100).round(0) %>% + Weight <%= (data["weight"].to_f * 100).round(0) %>%
"> <% if data["normalized_value"].present? %> @@ -178,7 +178,7 @@
%">
- 百分位 <%= data["percentile"].to_f.round(1) %>% + Percentile <%= data["percentile"].to_f.round(1) %>%
<% end %>
@@ -197,7 +197,7 @@ - 查看因子矩阵 + View Factor Matrix <% end %> <%= button_to generate_admin_trading_signals_path(asset_id: @signal.asset_id), method: :post, class: "signal-action-btn signal-action-btn--primary" do %> @@ -206,7 +206,7 @@ - 重新生成信号 + Regenerate Signal <% end %> diff --git a/app/views/ai_analysis/show.html.erb b/app/views/ai_analysis/show.html.erb index e4b9a08..c02e36b 100644 --- a/app/views/ai_analysis/show.html.erb +++ b/app/views/ai_analysis/show.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "AI 分析结果" %> +<% content_for :title, "AI Analysis Result" %>
diff --git a/app/views/allocation_decisions/index.html.erb b/app/views/allocation_decisions/index.html.erb index 8e72ccb..9301dbe 100644 --- a/app/views/allocation_decisions/index.html.erb +++ b/app/views/allocation_decisions/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "配置建议记录 - SmartTrader" %> +<% content_for :title, "Allocation Records - SmartTrader" %>
@@ -14,17 +14,17 @@ <% end %> -

配置建议记录

+

Allocation Records

- <%= link_to "返回操盘手", traders_path, class: "btn btn-secondary" %> + <%= link_to "Back to Traders", traders_path, class: "btn btn-secondary" %>
-

最近 100 条 Recommendation

+

Recent 100 Recommendations

<% if @allocation_decisions.any? %> @@ -32,14 +32,14 @@
资产信号类型置信度原因说明关键因子生成时间操作AssetSignal TypeConfidenceReasoningKey FactorsGenerated AtActions
- <%= link_to "查看", admin_trading_signal_path(signal), class: "action-link" %> + <%= link_to "View", admin_trading_signal_path(signal), class: "action-link" %>
- - - - - - - - + + + + + + + + @@ -52,7 +52,7 @@ - + <% end %> @@ -60,7 +60,7 @@ <% else %>
-

暂无配置建议记录

+

No allocation records yet

<% end %> diff --git a/app/views/allocation_decisions/show.html.erb b/app/views/allocation_decisions/show.html.erb index 7c06f96..77589a9 100644 --- a/app/views/allocation_decisions/show.html.erb +++ b/app/views/allocation_decisions/show.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "配置建议详情 - SmartTrader" %> +<% content_for :title, "Allocation Details - SmartTrader" %>
@@ -14,12 +14,12 @@ <% end %> -

配置建议详情

+

Allocation Details

- <%= button_to "执行建议", execute_allocation_decision_path(@allocation_decision), method: :post, class: "btn btn-primary", data: { turbo_confirm: "确认执行这条配置建议?" } %> + <%= button_to "Execute Recommendation", execute_allocation_decision_path(@allocation_decision), method: :post, class: "btn btn-primary", data: { turbo_confirm: "Confirm execution of this allocation recommendation?" } %> <%= link_to @allocation_decision.trader.name, @allocation_decision.trader, class: "btn btn-secondary" %> - <%= link_to "返回列表", allocation_decisions_path, class: "btn btn-ghost" %> + <%= link_to "Back to List", allocation_decisions_path, class: "btn btn-ghost" %>
@@ -38,40 +38,40 @@
-

基本信息

+

Basic Information

- 操盘手 + Trader <%= @allocation_decision.trader.name %>
- 建议日期 + Recommendation Date <%= @allocation_decision.decision_date %>
- 来源 + Source <%= @allocation_decision.source %>
- 模型 + Model <%= @allocation_decision.llm_model_name.presence || "-" %>
- 生成状态 + Generation Status <%= @allocation_decision.status %>
- 校验状态 + Validation Status <%= @allocation_decision.validation_status %>
- 选中策略 + Selected Strategy <%= @allocation_decision.selected_strategy.presence || "-" %>
- 生成时间 + Generated At <%= @allocation_decision.generated_at || @allocation_decision.created_at %>
@@ -79,17 +79,17 @@
-

Recommendation 内容

+

Recommendation Content

<% if @recommendation[:market_analysis].present? %>
- 市场分析 + Market Analysis <%= @recommendation[:market_analysis] %>
- 配置摘要 + Allocation Summary <%= @recommendation[:summary] %>
@@ -98,12 +98,12 @@
日期操盘手策略来源模型生成状态校验状态查看DateTraderStrategySourceModelStatusValidationView
<%= decision.llm_model_name.presence || "-" %> <%= decision.status %> <%= decision.validation_status %><%= link_to "详情", allocation_decision_path(decision), class: "btn btn-ghost btn-sm" %><%= link_to "Details", allocation_decision_path(decision), class: "btn btn-ghost btn-sm" %>
- - - - - - + + + + + + @@ -120,7 +120,7 @@ <% end %> <% else %> - + <% end %> @@ -129,13 +129,13 @@ <% if @recommendation[:detailed_reasoning].present? %>
-

配置理由详解

+

Detailed Allocation Reasoning

<%= @recommendation[:detailed_reasoning] %>

<% end %> <% else %>
-

这条 recommendation 当前没有可展示的结构化内容。

+

This recommendation currently has no structured content to display.

<% if @allocation_decision.error_message.present? %>

<%= @allocation_decision.error_message %>

<% end %> @@ -145,7 +145,7 @@
-

原始 JSON

+

Raw JSON

<%= JSON.pretty_generate(@allocation_decision.recommendation_payload) %>
@@ -154,32 +154,32 @@ <% if latest_task.present? %>
-

最近执行结果

+

Latest Execution Result

- 状态 + Status <%= latest_task.status %>
- 执行日期 + Execution Date <%= latest_task.run_on %>
- 执行后现金 + Ending Cash <%= number_to_currency(latest_task.ending_cash, unit: "$", precision: 2) %>
- 组合净值 + Portfolio Value <%= number_to_currency(latest_task.portfolio_value, unit: "$", precision: 2) %>
-

执行摘要

-

<%= latest_task.summary.presence || "暂无摘要" %>

-

<%= link_to "查看任务详情", allocation_task_path(latest_task), class: "text-link" %>

+

Execution Summary

+

<%= latest_task.summary.presence || "No summary" %>

+

<%= link_to "View Task Details", allocation_task_path(latest_task), class: "text-link" %>

<% end %> diff --git a/app/views/allocation_previews/show.html.erb b/app/views/allocation_previews/show.html.erb index e1f82e5..80f8723 100644 --- a/app/views/allocation_previews/show.html.erb +++ b/app/views/allocation_previews/show.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "AI配置建议 - #{@trader.name} - SmartTrader" %> +<% content_for :title, "AI Allocation Recommendation - #{@trader.name} - SmartTrader" %>
@@ -16,10 +16,10 @@ <% end %> -

AI配置建议

+

AI Allocation Recommendation

- <%= link_to "返回操盘手", @trader, class: "btn btn-secondary" %> + <%= link_to "Back to Trader", @trader, class: "btn btn-secondary" %>
@@ -28,15 +28,15 @@
-

操盘手信息

+

Trader Information

- 名称 + Name <%= @preview[:trader][:name] %>
- 风险偏好 + Risk Preference <%= @preview[:trader][:display_risk_level] %> @@ -44,7 +44,7 @@
- 可用资金 + Available Capital <%= number_to_currency(@preview[:trader][:current_capital], unit: "$", precision: 2) %>
@@ -53,13 +53,13 @@
-

AI 配置建议

+

AI Allocation Recommendation

<%= turbo_frame_tag "recommendation", src: recommendation_trader_allocation_preview_path(@trader), loading: :lazy do %>
-

AI 正在分析市场数据,请稍候...

+

AI is analyzing market data, please wait...

<% end %>
@@ -67,20 +67,20 @@
-

使用的策略 (Strategies)

+

Strategies Used

<% if @preview[:strategies].any? %>
资产操作比例金额 (USD)数量理由AssetActionAllocationAmount (USD)SharesReason
暂无资产配置明细No asset allocation details
- - - - - - - + + + + + + + @@ -88,7 +88,7 @@ - + @@ -98,10 +98,10 @@
市场环境策略名称最大持仓买入阈值单资产上限现金保留状态Market ConditionStrategy NameMax PositionsBuy ThresholdMax Position SizeCash ReserveStatus
<%= strategy[:display_market_condition] %> <%= strategy[:name] %><%= strategy[:max_positions] %> 个<%= strategy[:max_positions] %> <%= (strategy[:buy_signal_threshold] * 100).to_i %>% <%= (strategy[:max_position_size] * 100).to_i %>% <%= (strategy[:min_cash_reserve] * 100).to_i %>%
- + <% else %>
-

暂无策略数据

+

No strategy data

<% end %>
@@ -109,17 +109,17 @@
-

使用的信号 (Signals)

+

Signals Used

<% if @preview[:signals].any? %>
- - - - + + + + @@ -148,7 +148,7 @@ <% else %>
-

暂无信号数据

+

No signal data

<% end %> @@ -156,14 +156,14 @@
-

使用的因子 (Factors)

+

Factors Used

<% if @preview[:factors].any? && @preview[:factors].any? { |f| f[:factors].any? } %>
资产信号置信度理由AssetSignalConfidenceReason
- + <% @preview[:factors].first[:factors].each do |factor| %> <% end %> @@ -187,15 +187,15 @@ <% else %>
-

暂无因子数据

+

No factor data

<% end %>
- <%= link_to "返回操盘手", @trader, class: "btn btn-secondary" %> - <%= link_to "返回列表", traders_path, class: "btn btn-ghost" %> + <%= link_to "Back to Trader", @trader, class: "btn btn-secondary" %> + <%= link_to "Back to List", traders_path, class: "btn btn-ghost" %>
diff --git a/app/views/allocation_tasks/index.html.erb b/app/views/allocation_tasks/index.html.erb index a769d98..9ade959 100644 --- a/app/views/allocation_tasks/index.html.erb +++ b/app/views/allocation_tasks/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "执行任务记录 - SmartTrader" %> +<% content_for :title, "Execution Task Records - SmartTrader" %>
@@ -14,17 +14,17 @@ <% end %> -

执行任务记录

+

Execution Task Records

- <%= link_to "配置建议记录", allocation_decisions_path, class: "btn btn-secondary" %> + <%= link_to "Allocation Records", allocation_decisions_path, class: "btn btn-secondary" %>
-

最近 100 条 Execution Task

+

Recent 100 Execution Tasks

<% if @allocation_tasks.any? %> @@ -32,13 +32,13 @@
资产Asset<%= factor[:name] %>
- - - - - - - + + + + + + + @@ -51,12 +51,12 @@ - + <% end %> @@ -64,7 +64,7 @@ <% else %>
-

暂无执行任务记录

+

No execution task records

<% end %> diff --git a/app/views/allocation_tasks/show.html.erb b/app/views/allocation_tasks/show.html.erb index fc9487e..650715b 100644 --- a/app/views/allocation_tasks/show.html.erb +++ b/app/views/allocation_tasks/show.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "执行任务详情 - SmartTrader" %> +<% content_for :title, "Execution Task Details - SmartTrader" %>
@@ -14,61 +14,61 @@ <% end %> -

执行任务详情

+

Execution Task Details

<%= link_to @allocation_task.trader.name, @allocation_task.trader, class: "btn btn-secondary" %> <% if @allocation_task.allocation_decision.present? %> - <%= link_to "查看建议", allocation_decision_path(@allocation_task.allocation_decision), class: "btn btn-secondary" %> + <%= link_to "View Recommendation", allocation_decision_path(@allocation_task.allocation_decision), class: "btn btn-secondary" %> <% end %> - <%= link_to "返回列表", allocation_tasks_path, class: "btn btn-ghost" %> + <%= link_to "Back to List", allocation_tasks_path, class: "btn btn-ghost" %>
-

基本信息

+

Basic Information

- 操盘手 + Trader <%= @allocation_task.trader.name %>
- 执行日期 + Execution Date <%= @allocation_task.run_on %>
- 状态 + Status <%= @allocation_task.status %>
- 开始时间 + Start Time <%= @allocation_task.started_at || "-" %>
- 结束时间 + End Time <%= @allocation_task.completed_at || "-" %>
- 执行前现金 + Starting Cash <%= number_to_currency(@allocation_task.starting_cash, unit: "$", precision: 2) %>
- 执行后现金 + Ending Cash <%= number_to_currency(@allocation_task.ending_cash, unit: "$", precision: 2) %>
- 组合净值 + Portfolio Value <%= number_to_currency(@allocation_task.portfolio_value, unit: "$", precision: 2) %>
<% if @allocation_task.summary.present? %>
-

执行摘要

+

Execution Summary

<%= @allocation_task.summary %>

<% end %> @@ -82,7 +82,7 @@
-

执行 Payload

+

Execution Payload

<%= JSON.pretty_generate(@allocation_task.execution_payload || {}) %>
@@ -90,18 +90,18 @@ <% if @allocation_task.trader_trades.recent.any? %>
-

交易流水

+

Trade History

日期操盘手状态现金净值建议查看DateTraderStatusCashPortfolio ValueRecommendationView
<%= number_to_currency(task.portfolio_value, unit: "$", precision: 2) %> <% if task.allocation_decision.present? %> - <%= link_to "建议 ##{task.allocation_decision_id}", allocation_decision_path(task.allocation_decision), class: "text-link" %> + <%= link_to "Recommendation ##{task.allocation_decision_id}", allocation_decision_path(task.allocation_decision), class: "text-link" %> <% else %> - <% end %> <%= link_to "详情", allocation_task_path(task), class: "btn btn-ghost btn-sm" %><%= link_to "Details", allocation_task_path(task), class: "btn btn-ghost btn-sm" %>
- - - - - - + + + + + + diff --git a/app/views/assets/analysis.html.erb b/app/views/assets/analysis.html.erb index 5d8c87c..17ee067 100644 --- a/app/views/assets/analysis.html.erb +++ b/app/views/assets/analysis.html.erb @@ -2,13 +2,13 @@
- <%= link_to '← 返回', market_asset_path(@asset), + <%= link_to '← Back', market_asset_path(@asset), class: "text-blue-600 hover:text-blue-700 font-medium" %>

- <%= @asset.symbol %> AI 分析 + <%= @asset.symbol %> AI Analysis

<%= @asset.name %>

@@ -20,16 +20,16 @@
-

分析选项

+

Analysis Options

<% [24, 48, 72, 168].each do |hours| %> - <%= link_to "#{hours}小时", analysis_market_asset_path(@asset, hours:), + <%= link_to "#{hours}h", analysis_market_asset_path(@asset, hours:), class: "px-4 py-2 rounded-lg #{hours == @analysis_hours ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'}" %> <% end %>
@@ -37,16 +37,16 @@
@@ -54,7 +54,7 @@
@@ -64,7 +64,7 @@ @@ -75,22 +75,22 @@

- + - 趋势分析 + Trend Analysis

-

趋势方向

+

Trend Direction

-

支撑位

+

Support Level

-

阻力位

+

Resistance Level

@@ -102,23 +102,23 @@ - 交易信号 + Trading Signal
-

推荐操作

+

Recommended Action

-

置信度

+

Confidence

- ⚠️ 交易有风险,请谨慎操作。本分析仅供参考,不构成投资建议。 + ⚠️ Trading involves risk, please trade with caution. This analysis is for reference only and does not constitute investment advice.

@@ -127,24 +127,24 @@

- + - 风险评估 + Risk Assessment

-

波动性

+

Volatility

-

流动性

+

Liquidity

-

风险因素

+

Risk Factors

@@ -155,12 +155,12 @@ - AI 深度洞察 + AI Deep Insight

- 点击"开始分析"后,AI 将提供详细的市场分析。 + Click "Start Analysis" and AI will provide detailed market analysis.

@@ -194,12 +194,12 @@ displayAnalysisResults(result.data, mode === 'quick'); } else { loadingDiv.classList.add('hidden'); - alert('分析失败: ' + (result.error || '未知错误')); + alert('Analysis failed: ' + (result.error || 'Unknown error')); } }) .catch(error => { loadingDiv.classList.add('hidden'); - alert('网络错误: ' + error.message); + alert('Network error: ' + error.message); }); } @@ -221,9 +221,9 @@ function displayQuickResults(data) { // Trend Direction const trendMap = { - bullish: '看涨 ↗', - bearish: '看跌 ↘', - neutral: '中性 →' + bullish: 'Bullish ↗', + bearish: 'Bearish ↘', + neutral: 'Neutral →' }; const trendColors = { bullish: 'text-green-600', @@ -231,7 +231,7 @@ neutral: 'text-gray-600' }; - document.getElementById('trend-direction').textContent = trendMap[data.trend_direction] || '未知'; + document.getElementById('trend-direction').textContent = trendMap[data.trend_direction] || 'Unknown'; document.getElementById('trend-direction').className = `text-3xl font-bold ${trendColors[data.trend_direction] || 'text-gray-600'}`; // Trading Signal @@ -241,13 +241,13 @@ hold: 'bg-yellow-500 text-white' }; const signalMap = { - buy: '买入', - sell: '卖出', - hold: '持有' + buy: 'Buy', + sell: 'Sell', + hold: 'Hold' }; const signalDiv = document.getElementById('trading-signal'); - signalDiv.textContent = signalMap[data.trading_signal] || '持有'; + signalDiv.textContent = signalMap[data.trading_signal] || 'Hold'; signalDiv.className = `text-4xl font-bold py-2 px-4 rounded-lg ${signalColors[data.trading_signal] || 'bg-gray-500 text-white'}`; document.getElementById('signal-confidence').textContent = data.confidence ? data.confidence.toUpperCase() : '-'; @@ -257,15 +257,15 @@ document.getElementById('support-level').textContent = '-'; document.getElementById('volatility-level').textContent = data.volatility ? data.volatility.toFixed(2) : '-'; document.getElementById('liquidity-level').textContent = data.volume_avg ? formatVolume(data.volume_avg) : '-'; - document.getElementById('factors-list').innerHTML = '

快速模式仅提供基础技术分析

'; + document.getElementById('factors-list').innerHTML = '

Quick mode provides basic technical analysis only

'; } function displayFullResults(data) { // Trend Direction const trendMap = { - bullish: '看涨 ↗', - bearish: '看跌 ↘', - neutral: '中性 →' + bullish: 'Bullish ↗', + bearish: 'Bearish ↘', + neutral: 'Neutral →' }; const trendColors = { bullish: 'text-green-600', @@ -273,7 +273,7 @@ neutral: 'text-gray-600' }; - document.getElementById('trend-direction').textContent = trendMap[data.trend_direction] || '未知'; + document.getElementById('trend-direction').textContent = trendMap[data.trend_direction] || 'Unknown'; document.getElementById('trend-direction').className = `text-3xl font-bold ${trendColors[data.trend_direction] || 'text-gray-600'}`; // Support & Resistance @@ -287,23 +287,23 @@ hold: 'bg-yellow-500 text-white' }; const signalMap = { - buy: '买入', - sell: '卖出', - hold: '持有' + buy: 'Buy', + sell: 'Sell', + hold: 'Hold' }; const signalDiv = document.getElementById('trading-signal'); - signalDiv.textContent = signalMap[data.trading_signal] || '持有'; + signalDiv.textContent = signalMap[data.trading_signal] || 'Hold'; signalDiv.className = `text-4xl font-bold py-2 px-4 rounded-lg ${signalColors[data.trading_signal] || 'bg-gray-500 text-white'}`; document.getElementById('signal-confidence').textContent = data.confidence ? data.confidence.toUpperCase() : '-'; // Risk Assessment const volatilityMap = { - low: '低', - medium: '中', - high: '高', - extreme: '极高' + low: 'Low', + medium: 'Medium', + high: 'High', + extreme: 'Extreme' }; document.getElementById('volatility-level').textContent = volatilityMap[data.volatility_level] || '-'; document.getElementById('liquidity-level').textContent = data.volume_avg ? formatVolume(data.volume_avg) : '-'; @@ -315,7 +315,7 @@ `
${factor}
` ).join(''); } else { - factorsList.innerHTML = '

无特别风险因素

'; + factorsList.innerHTML = '

No specific risk factors

'; } // AI Insight diff --git a/app/views/assets/index.html.erb b/app/views/assets/index.html.erb index 8d65c74..def50fc 100644 --- a/app/views/assets/index.html.erb +++ b/app/views/assets/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "资产数据采集 - SmartTrader" %> +<% content_for :title, "Asset Data Collection - SmartTrader" %>
@@ -16,7 +16,7 @@ <% end %> -

资产数据采集

+

Asset Data Collection

@@ -25,7 +25,7 @@ - 触发采集 + Trigger Collection <%= link_to "/sidekiq", class: "btn btn-secondary btn--icon", target: "_blank", rel: "noopener" do %> @@ -34,7 +34,7 @@ - 任务队列 + Job Queue <% end %>
@@ -60,7 +60,7 @@
<%= @assets.count %> - 监控资产 + Monitored Assets
@@ -73,7 +73,7 @@
<%= AssetSnapshot.count %> - 数据快照 + Data Snapshots
@@ -81,7 +81,7 @@
-

热门资产

+

Popular Assets

<% end %>
- + Hot TOP
- 查看详情 + View Details @@ -153,7 +153,7 @@
<% end %> <% else %> -
暂无热门资产数据
+
No popular assets data yet
<% end %>
@@ -161,8 +161,8 @@
-

所有资产

-

实时市场数据监控

+

All Assets

+

Real-time market data monitoring

<% if @assets.any? %> @@ -217,12 +217,12 @@ <%= asset.latest_snapshot.change_percent >= 0 ? '+' : '' %><%= asset.latest_snapshot.change_percent.round(2) %>% - 24小时 + 24h <% else %>
- - 24小时 + 24h
<% end %>
@@ -230,11 +230,11 @@ <%= asset.last_updated&.strftime('%H:%M') || '--:--' %> - <%= asset.asset_snapshots.count %> 快照 + <%= asset.asset_snapshots.count %> snapshots
- 查看详情 + View Details @@ -251,10 +251,10 @@
-

暂无资产数据

-

等待数据采集任务开始...

+

No Asset Data Yet

+

Waiting for data collection to start...

<% end %> @@ -263,7 +263,7 @@
<%= paginate @assets, window: 2, class: "pagination" %>
- 共 <%= @assets.total_count %> 个资产,当前第 <%= @assets.current_page %> / <%= @assets.total_pages %> 页 + Total <%= @assets.total_count %> assets, Page <%= @assets.current_page %> of <%= @assets.total_pages %>
<% end %> @@ -285,14 +285,14 @@ const result = await response.json(); if (result.success) { - showToast('数据采集已触发!', 'success'); + showToast('Data collection triggered!', 'success'); setTimeout(() => location.reload(), 2000); } else { - showToast('触发失败: ' + (result.error || '未知错误'), 'error'); + showToast('Failed: ' + (result.error || 'Unknown error'), 'error'); } } catch (error) { console.error('Error triggering collection:', error); - showToast('网络错误,请稍后重试', 'error'); + showToast('Network error, please try again later', 'error'); } } diff --git a/app/views/assets/show.html.erb b/app/views/assets/show.html.erb index 07a295d..4b3bb1a 100644 --- a/app/views/assets/show.html.erb +++ b/app/views/assets/show.html.erb @@ -28,7 +28,7 @@
- <%= link_to "返回列表", market_assets_path, class: "btn btn-ghost" %> + <%= link_to "Back to List", market_assets_path, class: "btn btn-ghost" %>
@@ -43,16 +43,16 @@
-
资产详情
+
Asset Details

<%= @asset.name %>

- 在 <%= @asset.exchange %> 交易 · 以 <%= @asset.quote_currency %> 计价 + Traded on <%= @asset.exchange %> · Quoted in <%= @asset.quote_currency %>

<% if @asset.current_price %>
- 当前价格 + Current Price <%= number_to_currency(@asset.current_price, precision: 4) %> <%= @asset.quote_currency %> @@ -61,7 +61,7 @@ <% end %> <% if @asset.latest_snapshot && @asset.latest_snapshot.change_percent %>
- 24小时 + 24h <%= @asset.latest_snapshot.change_percent >= 0 ? '+' : '' %><%= @asset.latest_snapshot.change_percent.round(2) %>% @@ -69,7 +69,7 @@ <% end %> <% if @asset.latest_snapshot && @asset.latest_snapshot.volume %>
- 成交量 + Volume <%= number_with_delimiter(@asset.latest_snapshot.volume.to_i) %> @@ -88,11 +88,11 @@ - 基本信息 + Basic Information
- 资产类型 + Asset Type <% case @asset.asset_type.to_s.downcase %> @@ -127,35 +127,35 @@
- 状态 + Status - <%= @asset.active? ? '活跃' : '非活跃' %> + <%= @asset.active? ? 'Active' : 'Inactive' %>
- 交易所 + Exchange <%= @asset.exchange %>
- 计价货币 + Quote Currency <%= @asset.quote_currency %>
- 最后更新 + Last Updated <%= @asset.last_updated&.strftime('%Y-%m-%d %H:%M') || '-' %>
- 数据快照数 + Data Snapshots <%= @snapshots.count %>
<% if @asset.coingecko_id.present? || @asset.yahoo_symbol.present? %>
-

外部标识符

+

External Identifiers

<% if @asset.coingecko_id.present? %>
@@ -181,13 +181,13 @@ - 市场数据 - (基于最新快照) + Market Data + (Based on latest snapshot)
<% if @asset.current_price %>
- 当前价格 + Current Price <%= number_to_currency(@asset.current_price, precision: 4) %> <%= @asset.quote_currency %> @@ -196,7 +196,7 @@ <% end %> <% if @asset.latest_snapshot && @asset.latest_snapshot.change_percent %>
- 24小时变化 + 24h Change <%= @asset.latest_snapshot.change_percent >= 0 ? '+' : '' %><%= @asset.latest_snapshot.change_percent.round(2) %>% @@ -204,7 +204,7 @@ <% end %> <% if @asset.latest_snapshot && @asset.latest_snapshot.volume %>
- 成交量 + Volume <%= number_with_delimiter(@asset.latest_snapshot.volume.to_i) %> @@ -212,7 +212,7 @@ <% end %> <% if @asset.market_cap %>
- 市值 + Market Cap <%= number_to_human(@asset.market_cap, format: '%n%u', units: { thousand: 'K', million: 'M', billion: 'B', trillion: 'T' }) %> @@ -220,13 +220,13 @@ <% end %> <% if @asset.market_cap_rank %>
- 市值排名 + Market Cap Rank #<%= @asset.market_cap_rank %>
<% end %> <% if @asset.latest_snapshot&.captured_at %>
- 快照时间 + Snapshot Time <%= @asset.latest_snapshot.captured_at.strftime('%Y-%m-%d %H:%M') %> @@ -242,10 +242,10 @@ - 历史快照时间范围 + Historical Snapshot Time Range
- 选择时间范围: + Select Time Range: <% ['all', '1h', '6h', '24h', '7d', '30d'].each do |tf| %> <%= link_to timeframe_label(tf), market_asset_path(@asset, timeframe: tf), class: "timeframe-btn #{tf == @timeframe ? 'timeframe-btn--active' : ''}" %> @@ -264,17 +264,17 @@ - 历史快照记录 - <%= @snapshots.count %> 条记录 + Historical Snapshots + <%= @snapshots.count %> records <% if @snapshots.any? %>
-
日期时间
-
价格
-
涨跌幅
-
成交量
+
Date & Time
+
Price
+
Change %
+
Volume
<% @snapshots.each do |snapshot| %> @@ -303,8 +303,8 @@
-

暂无数据快照

-

该资产暂时没有历史快照记录

+

No Data Snapshots Yet

+

This asset has no historical snapshot records yet.

<% end %>
@@ -312,7 +312,7 @@
- <%= link_to "返回列表", market_assets_path, class: "btn btn-ghost" %> + <%= link_to "Back to List", market_assets_path, class: "btn btn-ghost" %>
diff --git a/app/views/home/index.html.erb b/app/views/home/index.html.erb index 17f8b40..0a6a2b9 100644 --- a/app/views/home/index.html.erb +++ b/app/views/home/index.html.erb @@ -77,13 +77,13 @@ 01

Trader Profile

-

操盘手信息管理

+

Trader Profile Management

LLM
- AI 解析文字描述,自动生成操盘手性格特征、交易风格及资产配置建议 + AI parses text descriptions to automatically generate trader personality, trading style, and asset allocation suggestions
CRUD @@ -91,7 +91,7 @@ Asset Allocation
<%= link_to traders_path, class: "module-card__action module-card__action--active" do %> - 进入模块 + Enter Module @@ -113,14 +113,14 @@ 02

Factor System

-

交易因子系统

+

Trading Factor System

LLM Quant
- 多维度因子分析系统,包含动量、波动率、贝塔等6个核心因子,AI综合分析生成交易信号 + Multi-dimensional factor analysis system with 6 core factors including momentum, volatility, beta. AI comprehensively analyzes to generate trading signals
6 Factors @@ -128,7 +128,7 @@ Correlation
<%= link_to admin_factor_definitions_path, class: "module-card__action module-card__action--active" do %> - 进入模块 + Enter Module @@ -148,14 +148,14 @@

Signal Plaza

-

信号广场

+

Trading Signals

LLM AI
- AI 分析监控资产的交易信号:黄金、BTC、英伟达等,提供实时告警 + AI analyzes trading signals for monitored assets: gold, BTC, NVIDIA, etc., providing real-time alerts
Buy/Sell/Hold @@ -163,7 +163,7 @@ Multi-asset
<%= link_to admin_trading_signals_path, class: "module-card__action module-card__action--active highlighted" do %> - 进入模块 + Enter Module @@ -184,14 +184,14 @@ 04

AI Analysis

-

AI 智能分析

+

AI Smart Analysis

LLM AI
- AI 驱动的智能分析引擎,提供市场洞察和投资决策支持 + AI-powered intelligent analysis engine providing market insights and investment decision support
Deep Analysis @@ -199,7 +199,7 @@ AI Reports
<%= link_to ai_analysis_path, class: "module-card__action module-card__action--active" do %> - 进入模块 + Enter Module @@ -218,14 +218,14 @@ 05

Asset Data Collection

-

资产动态信息采集

+

Asset Data Collection

MCP Skills
- 后台定时采集股票、加密货币等资产动态数据 + Background scheduled collection of stock, cryptocurrency and other asset dynamic data
Stocks @@ -233,7 +233,7 @@ Auto-fetch
<%= link_to market_assets_path, class: "module-card__action module-card__action--active" do %> - 进入模块 + Enter Module @@ -254,13 +254,13 @@ 06

Portfolio Dashboard

-

操盘手资产管理页面

+

Trader Asset Management

LLM
- 显示操盘手投资组合盈亏图表,持仓详情及 AI 生成的分析报告 + Display trader portfolio P/L charts, holding details, and AI-generated analysis reports
Charts @@ -268,7 +268,7 @@ AI Reports
<%= link_to portfolio_dashboard_path, class: "module-card__action module-card__action--active" do %> - 进入模块 + Enter Module @@ -291,13 +291,13 @@ 07

Investment Info

-

投资信息 Skill

+

Investment Info Skill

Skills
- 获取最新投资新闻、市场分析报告和特定资产研究信息 + Get latest investment news, market analysis reports and specific asset research information
News Feed @@ -327,14 +327,14 @@ 08

Market Sentiment

-

市场情绪指数

+

Market Sentiment Index

CLI LLM
- Claude Code CLI 分析市场情绪,生成恐惧贪婪指数和历史趋势图 + Claude Code CLI analyzes market sentiment, generates fear greed index and historical trend chart
Fear/Greed @@ -362,14 +362,14 @@ 09

Auto Allocation

-

定时资产配置任务

+

Scheduled Asset Allocation

LLM CLI
- 为操盘手分配资金,根据 AI 分析动态调整资产配置策略 + Allocate capital for traders, dynamically adjust asset allocation strategies based on AI analysis
$100K Start @@ -401,13 +401,13 @@ 10

Performance Ranking

-

资产配置盈亏排名

+

Asset Allocation P/L Ranking

LLM
- 操盘手盈亏排名列表,展示收益率、夏普比率等指标和个性化分析 + Trader P/L ranking list displaying return rates, Sharpe ratios, and personalized analysis
Leaderboard @@ -437,13 +437,13 @@ 11

Investor Personas

-

投资人性格模板 Skill

+

Investor Profile Templates

Skills
- 巴菲特、索罗斯等著名投资人投资风格模板库,快速创建名人风格操盘手 + Famous investor style template library including Buffett, Soros, etc. Quickly create celebrity-style traders
Berkshire @@ -479,7 +479,7 @@

Portfolio Analysis

-

持仓分析 Skill

+

Holdings Analysis

@@ -492,7 +492,7 @@

Technical Indicators

-

技术指标解读 Skill

+

Technical Analysis

@@ -507,7 +507,7 @@

Trading Strategies

-

交易策略模板 Skill

+

Strategy Templates

diff --git a/app/views/portfolio_dashboards/show.html.erb b/app/views/portfolio_dashboards/show.html.erb index a1cbffe..fbcd576 100644 --- a/app/views/portfolio_dashboards/show.html.erb +++ b/app/views/portfolio_dashboards/show.html.erb @@ -16,11 +16,11 @@ <% end %>

Portfolio Dashboard

-

操盘手组合总览、执行结果与持仓摘要

+

Trader Portfolio Overview, Execution Results and Holdings Summary

- <%= link_to "操盘手管理", traders_path, class: "btn btn-secondary" %> + <%= link_to "Traders", traders_path, class: "btn btn-secondary" %>
@@ -35,23 +35,23 @@
- 总资产 + Total Equity <%= number_to_currency(@dashboard_stats[:total_equity], unit: "$", precision: 0) %>
- 累计盈亏 + Cumulative P/L "> <%= @dashboard_stats[:total_profit_loss] >= 0 ? "+" : "" %><%= number_to_currency(@dashboard_stats[:total_profit_loss], unit: "$", precision: 0) %>
- 持仓浮盈亏 + Unrealized P/L "> <%= @dashboard_stats[:total_unrealized_pnl] >= 0 ? "+" : "" %><%= number_to_currency(@dashboard_stats[:total_unrealized_pnl], unit: "$", precision: 0) %>
- 平均收益率 + Average Return "> <%= @dashboard_stats[:average_return] >= 0 ? "+" : "" %><%= @dashboard_stats[:average_return] %>% @@ -60,15 +60,15 @@
- 活跃操盘手 + Active Traders <%= @dashboard_stats[:active_traders] %>
- 当前持仓数 + Current Positions <%= @dashboard_stats[:total_positions] %>
- 已完成执行次数 + Completed Executions <%= @dashboard_stats[:completed_tasks] %>
@@ -77,13 +77,13 @@
P/L View -

组合净值与累计盈亏

+

Portfolio Equity and Cumulative P/L

- 图表继续基于 `portfolio_snapshots` 展示历史趋势;上方卡片与当前净值则按最新持仓价格实时盯市。 + Charts continue to display historical trends based on portfolio_snapshots; top cards and current equity are marked to market at latest holding prices.

- 最新总盈亏 + Latest Total P/L "> <%= @portfolio_chart[:latest_pnl] >= 0 ? "+" : "" %><%= number_to_currency(@portfolio_chart[:latest_pnl], unit: "$", precision: 0) %> @@ -94,10 +94,10 @@
- 总组合净值 + Total Portfolio Equity <%= number_to_currency(@portfolio_chart[:latest_value], unit: "$", precision: 0) %>
- + @@ -105,12 +105,12 @@
- 累计盈亏 + Cumulative P/L "> <%= @portfolio_chart[:latest_pnl] >= 0 ? "+" : "" %><%= number_to_currency(@portfolio_chart[:latest_pnl], unit: "$", precision: 0) %>
- + "> @@ -124,7 +124,7 @@
<% else %>
- 还没有足够的执行历史,暂时无法生成组合盈亏图表。 + Not enough execution history yet, unable to generate portfolio P/L chart.
<% end %>
@@ -160,17 +160,17 @@
- 净值 + Net Value <%= number_to_currency(row[:equity_value], unit: "$", precision: 0) %>
- 累计盈亏 + Cumulative P/L <%= row[:profit_loss] >= 0 ? '+' : '' %><%= number_to_currency(row[:profit_loss], unit: "$", precision: 0) %>
- 收益率 + Return Rate <%= row[:profit_loss_percent] >= 0 ? '+' : '' %><%= row[:profit_loss_percent] %>% @@ -179,13 +179,13 @@
- 收益曲线 + Return Curve <%= trader_chart[:latest_pnl] >= 0 ? '+' : '' %><%= number_to_currency(trader_chart[:latest_pnl], unit: "$", precision: 0) %>
<% if trader_chart[:has_points] %> - "> + "> "> @@ -194,43 +194,43 @@ <%= trader_chart[:end_label] %>
<% else %> -
执行历史不足,暂时没有可绘制的收益曲线。
+
Insufficient execution history, unable to plot return curve.
<% end %>
- 资产拆分 + Asset Breakdown
- 现金 <%= number_to_currency(row[:cash_value], unit: "$", precision: 0) %> - 持仓 <%= number_to_currency(row[:invested_value], unit: "$", precision: 0) %> + Cash <%= number_to_currency(row[:cash_value], unit: "$", precision: 0) %> + Holdings <%= number_to_currency(row[:invested_value], unit: "$", precision: 0) %>
- 最近执行 + Latest Execution <% if latest_task.present? %>
<%= latest_task.status.humanize %> <%= l(latest_task.created_at, format: :short) %>
<% else %> - 暂无执行记录 + No execution records <% end %>
- 已实现盈亏 + Realized P/L
<%= row[:realized_pnl] >= 0 ? '+' : '' %><%= number_to_currency(row[:realized_pnl], unit: "$", precision: 0) %> - 历史已兑现盈亏 + Historical realized P/L
- 持仓浮盈亏 + Unrealized P/L
<%= position_metrics[:unrealized_pnl] >= 0 ? '+' : '' %><%= number_to_currency(position_metrics[:unrealized_pnl], unit: "$", precision: 0) %> @@ -242,32 +242,32 @@
- 当前持仓 + Current Positions
<%= active_positions.size %> <% if active_positions.any? %> <%= active_positions.first(3).map { |position| position.asset.symbol }.join(", ") %> <% else %> - 空仓 + No positions <% end %>
- 最近交易 + Recent Trade <% if recent_trade.present? %>
<%= recent_trade.action.upcase %> <%= recent_trade.asset.symbol %> <%= l(recent_trade.executed_at, format: :short) %>
<% else %> - 暂无交易流水 + No trade history <% end %>
- <%= link_to "查看操盘手", trader_path(trader), class: "btn btn-secondary" %> + <%= link_to "View Trader", trader_path(trader), class: "btn btn-secondary" %>
<% end %> @@ -280,9 +280,9 @@
-

还没有可展示的模拟盘

-

先创建操盘手并生成 recommendation,Portfolio Dashboard 才会开始显示组合结果。

- <%= link_to "创建操盘手", new_trader_path, class: "btn btn-primary" %> +

No Simulated Accounts Yet

+

Create traders and generate recommendations first, Portfolio Dashboard will start displaying portfolio results.

+ <%= link_to "Create Trader", new_trader_path, class: "btn btn-primary" %>
<% end %> diff --git a/app/views/trader_reflections/show.html.erb b/app/views/trader_reflections/show.html.erb index 10f83f8..c4fa71c 100644 --- a/app/views/trader_reflections/show.html.erb +++ b/app/views/trader_reflections/show.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "#{@trader.name} - 交易反思报告" %> +<% content_for :title, "#{@trader.name} - Trading Reflection Report" %>
@@ -17,11 +17,11 @@ <% end %>
AI Analysis Report -

交易反思报告

+

Trading Reflection Report

- <%= button_to "重新生成", trader_trader_reflections_path(@trader), method: :post, class: "reflection-report__btn reflection-report__btn--primary" %> + <%= button_to "Regenerate", trader_trader_reflections_path(@trader), method: :post, class: "reflection-report__btn reflection-report__btn--primary" %>
@@ -59,7 +59,7 @@ - <%= @trader_reflection.reflection_period_start %> 至 <%= @trader_reflection.reflection_period_end %> + <%= @trader_reflection.reflection_period_start %> to <%= @trader_reflection.reflection_period_end %>
@@ -68,7 +68,7 @@ - 状态 + Status <%= @trader_reflection.status %>
@@ -76,7 +76,7 @@ - 来源 + Source <%= @trader_reflection.source %>
<% if @trader_reflection.generated_at.present? %> @@ -85,7 +85,7 @@ - 生成时间 + Generated At <%= l(@trader_reflection.generated_at, format: :short) %> <% end %> @@ -94,26 +94,26 @@
-

关键指标快照

+

Key Metrics Snapshot

<% metrics = @trader_reflection.metrics || {} %>
- 交易次数 + Trade Count <%= metrics["trade_count"] || 0 %>
- 完成任务数 + Completed Tasks <%= metrics["completed_task_count"] || 0 %>
- 累计盈亏 + Cumulative P/L <% total_pnl = metrics["total_profit_loss"] || 0 %> <%= number_to_currency(total_pnl, unit: "$", precision: 2) %>
- 持仓浮盈亏 + Unrealized P/L <% unrealized_pnl = metrics["unrealized_pnl"] || 0 %> <%= number_to_currency(unrealized_pnl, unit: "$", precision: 2) %> @@ -135,10 +135,10 @@
-

反思总结

+

Reflection Summary

- <%= @trader_reflection.llm_summary.presence || "暂无总结" %> + <%= @trader_reflection.llm_summary.presence || "No summary" %>

@@ -151,7 +151,7 @@ -

核心发现

+

Core Findings

<% findings = @trader_reflection.findings || {} %> @@ -162,10 +162,10 @@ - 优点 + Strengths
- <%= Array(findings["strengths"]).join(";").presence || "-" %> + <%= Array(findings["strengths"]).join("; ").presence || "-" %>
@@ -176,10 +176,10 @@ - 问题 + Issues
- <%= Array(findings["mistakes"]).join(";").presence || "-" %> + <%= Array(findings["mistakes"]).join("; ").presence || "-" %>
@@ -188,10 +188,10 @@ - 模式观察 + Pattern Observations
- <%= Array(findings["pattern_findings"]).join(";").presence || "-" %> + <%= Array(findings["pattern_findings"]).join("; ").presence || "-" %>
@@ -202,10 +202,10 @@ - 风险提示 + Risk Warnings
- <%= Array(findings["risk_issues"]).join(";").presence || "-" %> + <%= Array(findings["risk_issues"]).join("; ").presence || "-" %>
@@ -218,7 +218,7 @@ - 总体建议 + Overall Recommendation

<%= findings["recommendation"] %>

@@ -241,7 +241,7 @@ -

建议微调参数

+

Suggested Parameter Adjustments

<% current_strategy = @trader_reflection.trading_strategy || @trader.default_strategy %> @@ -249,25 +249,25 @@ <% if current_strategy.present? %>
-
当前生效策略
+
Current Active Strategy
- 策略名称:<%= current_strategy.name %>
- 市场环境:<%= current_strategy.display_market_condition %>
- 来源:<%= current_strategy.display_generated_by %> + Strategy Name: <%= current_strategy.name %>
+ Market Condition: <%= current_strategy.display_market_condition %>
+ Source: <%= current_strategy.display_generated_by %>
-
当前策略参数
+
Current Strategy Parameters
- 最大持仓数 <%= current_strategy.max_positions %>, - 买入阈值 <%= current_strategy.buy_signal_threshold %>, - 最大仓位 <%= current_strategy.max_position_size %>, - 最小现金保留 <%= current_strategy.min_cash_reserve %> + Max Positions <%= current_strategy.max_positions %>, + Buy Threshold <%= current_strategy.buy_signal_threshold %>, + Max Position Size <%= current_strategy.max_position_size %>, + Min Cash Reserve <%= current_strategy.min_cash_reserve %>

- 💡 本页建议只会作用于这套策略,不会自动修改其他市场环境策略。 + 💡 Recommendations on this page only apply to this strategy and will not automatically modify other market condition strategies.

<% end %> @@ -276,12 +276,12 @@
动作资产数量价格金额理由ActionAssetQuantityPriceAmountReason
- - - - - - + + + + + + @@ -324,10 +324,10 @@ - 已应用 + Applied <% else %> - <%= button_to "应用到这套策略", apply_adjustment_trader_trader_reflection_path(@trader, @trader_reflection, parameter: adjustment["parameter"]), method: :post, class: "reflection-report__btn reflection-report__btn--primary" %> + <%= button_to "Apply to Strategy", apply_adjustment_trader_trader_reflection_path(@trader, @trader_reflection, parameter: adjustment["parameter"]), method: :post, class: "reflection-report__btn reflection-report__btn--primary" %> <% end %> @@ -341,7 +341,7 @@ -

当前没有建议微调的参数,说明这次反思更偏向复盘和观察。

+

No parameter adjustments suggested, indicating this reflection is more focused on review and observation.

<% end %> @@ -356,17 +356,17 @@ -

已应用调整记录

+

Applied Adjustment Records

参数当前值建议后值方向原因操作ParameterCurrent ValueSuggested ValueDirectionReasonAction
- - - - - + + + + + @@ -397,7 +397,7 @@ - 返回操盘手详情 + Back to Trader Details <% end %> diff --git a/app/views/traders/_form.html.erb b/app/views/traders/_form.html.erb index 936f66d..32c8842 100644 --- a/app/views/traders/_form.html.erb +++ b/app/views/traders/_form.html.erb @@ -1,7 +1,7 @@ <%= form_with(model: trader, class: "trader-form") do |form| %> <% if trader.errors.any? %>
-

<%= pluralize(trader.errors.count, "个错误") %> 需要修复:

+

<%= pluralize(trader.errors.count, "error") %> needs to be fixed:

    <% trader.errors.full_messages.each do |message| %>
  • <%= message %>
  • @@ -11,49 +11,49 @@ <% end %>
    - <%= form.label :name, "名称", class: "form-label" %> - <%= form.text_field :name, class: "form-input", placeholder: "例如:巴菲特风格", maxlength: 100 %> - 给操盘手起个名字,便于识别 + <%= form.label :name, "Name", class: "form-label" %> + <%= form.text_field :name, class: "form-input", placeholder: "e.g., Buffett Style", maxlength: 100 %> + Give your trader a name for easy identification
    - <%= form.label :risk_level, "风险等级", class: "form-label" %> + <%= form.label :risk_level, "Risk Level", class: "form-label" %> <%= form.select :risk_level, options_for_select([ - ["保守型 - 注重本金保护", "conservative"], - ["平衡型 - 风险与收益兼顾", "balanced"], - ["激进型 - 追求高收益", "aggressive"] + ["Conservative - Capital Protection", "conservative"], + ["Balanced - Risk & Return Balance", "balanced"], + ["Aggressive - High Returns", "aggressive"] ], trader.risk_level), {}, class: "form-select" %> - 选择操盘手的风险偏好 + Select your trader's risk preference
    - <%= form.label :initial_capital, "初始资金", class: "form-label" %> + <%= form.label :initial_capital, "Initial Capital", class: "form-label" %>
    $ <%= form.number_field :initial_capital, class: "form-input form-input--with-prefix", min: 0, step: 0.01 %>
    - 操盘手的起始资金(默认 $100,000) + Starting capital for the trader (default $100,000)
    - <%= form.label :status, "状态", class: "form-label" %> + <%= form.label :status, "Status", class: "form-label" %> <%= form.select :status, options_for_select([ - ["启用", "active"], - ["停用", "inactive"] + ["Active", "active"], + ["Inactive", "inactive"] ], trader.status), {}, class: "form-select" %>
    - <%= form.label :description, "投资风格描述", class: "form-label" %> + <%= form.label :description, "Investment Style Description", class: "form-label" %> <%= form.text_area :description, class: "form-textarea", - placeholder: "描述您的投资风格,例如:\n我是稳健型投资者,注重长期价值投资。我喜欢持有优质蓝筹股,追求稳定的分红收益。我会严格控制仓位,保留足够的现金应对市场波动。", + placeholder: "Describe your investment style, e.g.:\nI am a conservative investor focused on long-term value investing. I like holding quality blue-chip stocks and pursuing stable dividend returns. I strictly control positions and keep enough cash to handle market volatility.", rows: 5, maxlength: 2000 %> @@ -62,12 +62,12 @@ - AI 将根据描述自动生成个性化的交易策略。描述越详细,策略越精准。 + AI will generate personalized trading strategies based on your description. The more detailed, the more precise the strategy.
    <%= form.submit class: "btn btn-primary" %> - <%= link_to "取消", traders_path, class: "btn btn-ghost" %> + <%= link_to "Cancel", traders_path, class: "btn btn-ghost" %>
    <% end %> diff --git a/app/views/traders/edit.html.erb b/app/views/traders/edit.html.erb index ee14e29..cc9bcea 100644 --- a/app/views/traders/edit.html.erb +++ b/app/views/traders/edit.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "编辑 #{@trader.name} - SmartTrader" %> +<% content_for :title, "Edit #{@trader.name} - SmartTrader" %>
    @@ -16,7 +16,7 @@ <% end %> -

    编辑 <%= @trader.name %>

    +

    Edit <%= @trader.name %>

    @@ -25,8 +25,8 @@
    -

    修改操盘手信息

    -

    修改投资风格描述后,AI 将重新生成交易策略

    +

    Edit Trader Information

    +

    After modifying investment style description, AI will regenerate trading strategies

    <%= render "form", trader: @trader %> diff --git a/app/views/traders/index.html.erb b/app/views/traders/index.html.erb index c0a23f8..659b593 100644 --- a/app/views/traders/index.html.erb +++ b/app/views/traders/index.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "操盘手管理 - SmartTrader" %> +<% content_for :title, "Traders - SmartTrader" %>
    @@ -16,11 +16,11 @@ <% end %> -

    操盘手管理

    +

    Traders

    - <%= link_to "配置建议记录", allocation_decisions_path, class: "btn btn-secondary" %> - <%= link_to "新建操盘手", new_trader_path, class: "btn btn-primary" %> + <%= link_to "Allocation Records", allocation_decisions_path, class: "btn btn-secondary" %> + <%= link_to "New Trader", new_trader_path, class: "btn btn-primary" %>
    @@ -58,15 +58,15 @@
    - 初始资金 + Initial Capital <%= number_to_currency(trader.initial_capital, unit: "$", precision: 0) %>
    - 当前资金 + Current Capital <%= number_to_currency(trader.current_capital_value, unit: "$", precision: 0) %>
    - 盈亏 + Profit/Loss <%= trader.profit_loss >= 0 ? '+' : '' %><%= number_to_currency(trader.profit_loss, unit: "$", precision: 0) %> (<%= trader.profit_loss_percent >= 0 ? '+' : '' %><%= trader.profit_loss_percent %>%) @@ -81,16 +81,16 @@ <% if trader.default_strategy.present? %>
    - 策略: + Strategy: <%= trader.default_strategy.name %> - (<%= trader.trading_strategies.count %>种市场环境) + (<%= trader.trading_strategies.count %> market conditions)
    <% end %>
    - <%= link_to "查看详情", trader, class: "btn btn-secondary" %> - <%= link_to "AI配置建议", trader_allocation_preview_path(trader), class: "btn btn-outline" %> - <%= link_to "编辑", edit_trader_path(trader), class: "btn btn-ghost" %> + <%= link_to "View Details", trader, class: "btn btn-secondary" %> + <%= link_to "AI Allocation", trader_allocation_preview_path(trader), class: "btn btn-outline" %> + <%= link_to "Edit", edit_trader_path(trader), class: "btn btn-ghost" %>
    <% end %> @@ -103,9 +103,9 @@
    -

    还没有操盘手

    -

    创建你的第一个 AI 操盘手,开始智能投资之旅

    - <%= link_to "创建操盘手", new_trader_path, class: "btn btn-primary" %> +

    No Traders Yet

    +

    Create your first AI trader to start your smart investment journey

    + <%= link_to "Create Trader", new_trader_path, class: "btn btn-primary" %>
    <% end %> diff --git a/app/views/traders/new.html.erb b/app/views/traders/new.html.erb index 4de831e..773032a 100644 --- a/app/views/traders/new.html.erb +++ b/app/views/traders/new.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "新建操盘手 - SmartTrader" %> +<% content_for :title, "New Trader - SmartTrader" %>
    @@ -16,7 +16,7 @@ <% end %> -

    新建操盘手

    +

    New Trader

    @@ -25,8 +25,8 @@
    -

    创建 AI 操盘手

    -

    输入投资风格描述,AI 将自动生成个性化的交易策略

    +

    Create AI Trader

    +

    Enter your investment style description, AI will automatically generate personalized trading strategies

    <%= render "form", trader: @trader %> diff --git a/app/views/traders/show.html.erb b/app/views/traders/show.html.erb index 67af74d..2921d78 100644 --- a/app/views/traders/show.html.erb +++ b/app/views/traders/show.html.erb @@ -19,11 +19,11 @@

    <%= @trader.name %>

    - <%= link_to "AI配置建议", trader_allocation_preview_path(@trader), class: "btn btn-primary" %> - <%= link_to "配置建议记录", allocation_decisions_path, class: "btn btn-secondary" %> - <%= link_to "执行任务记录", allocation_tasks_path, class: "btn btn-secondary" %> - <%= link_to "编辑", edit_trader_path(@trader), class: "btn btn-secondary" %> - <%= button_to "删除", @trader, method: :delete, class: "btn btn-danger", data: { turbo_confirm: "确定要删除这个操盘手吗?" } %> + <%= link_to "AI Allocation", trader_allocation_preview_path(@trader), class: "btn btn-primary" %> + <%= link_to "Allocation Records", allocation_decisions_path, class: "btn btn-secondary" %> + <%= link_to "Task Records", allocation_tasks_path, class: "btn btn-secondary" %> + <%= link_to "Edit", edit_trader_path(@trader), class: "btn btn-secondary" %> + <%= button_to "Delete", @trader, method: :delete, class: "btn btn-danger", data: { turbo_confirm: "Are you sure you want to delete this trader?" } %>
    @@ -44,38 +44,38 @@
    -

    基本信息

    +

    Basic Information

    - 风险等级 + Risk Level <%= @trader.display_risk_level %>
    - 状态 + Status <%= @trader.display_status %>
    - 初始资金 + Initial Capital <%= number_to_currency(@trader.initial_capital, unit: "$", precision: 2) %>
    - 当前资金 + Current Capital <%= number_to_currency(@latest_portfolio_snapshot&.portfolio_value || @trader.current_capital_value, unit: "$", precision: 2) %>
    - 盈亏 + Profit/Loss <% current_profit_loss = @latest_portfolio_snapshot&.profit_loss || @trader.profit_loss %> <%= current_profit_loss >= 0 ? '+' : '' %><%= number_to_currency(current_profit_loss, unit: "$", precision: 2) %>
    - 收益率 + Return Rate <% current_profit_loss_percent = @latest_portfolio_snapshot&.profit_loss_percent || @trader.profit_loss_percent %> <%= current_profit_loss_percent >= 0 ? '+' : '' %><%= current_profit_loss_percent %>% @@ -85,7 +85,7 @@ <% if @trader.description.present? %>
    -

    投资风格描述

    +

    Investment Style

    <%= @trader.description %>

    <% end %> @@ -94,8 +94,8 @@

    - 策略矩阵 - (AI 将根据市场环境自动选择策略) + Strategy Matrix + (AI will automatically select strategy based on market conditions)

    <% if @strategies.any? %> @@ -116,19 +116,19 @@
    - 最大持仓数 - <%= strategy.max_positions %> 个资产 + Max Positions + <%= strategy.max_positions %> assets
    - 买入信号阈值 + Buy Signal Threshold <%= (strategy.buy_signal_threshold * 100).to_i %>%
    - 单资产最大仓位 + Max Position Size <%= (strategy.max_position_size * 100).to_i %>%
    - 最小现金保留 + Min Cash Reserve <%= (strategy.min_cash_reserve * 100).to_i %>%
    @@ -143,43 +143,43 @@
    <% else %>
    -

    暂无交易策略,请编辑操盘手信息以生成策略

    - <%= link_to "编辑操盘手", edit_trader_path(@trader), class: "btn btn-secondary" %> +

    No trading strategies yet. Please edit trader information to generate strategies.

    + <%= link_to "Edit Trader", edit_trader_path(@trader), class: "btn btn-secondary" %>
    <% end %>
    -

    模拟盘概览

    +

    Simulation Overview

    - 最近执行状态 + Latest Execution Status <%= @latest_allocation_task&.status || "-" %>
    - 最近执行日期 + Latest Execution Date <%= @latest_allocation_task&.run_on || "-" %>
    - 当前持仓数 + Current Holdings Count <%= @trader_positions.size %>
    - 当前净值 + Current Net Value <%= number_to_currency(@latest_portfolio_snapshot&.portfolio_value || @trader.current_capital_value, unit: "$", precision: 2) %>
    <% if @latest_allocation_task.present? %>
    -

    最近执行摘要

    -

    <%= @latest_allocation_task.summary.presence || "暂无摘要" %>

    +

    Recent Execution Summary

    +

    <%= @latest_allocation_task.summary.presence || "No summary" %>

    - 现金:<%= number_to_currency(@latest_portfolio_snapshot&.cash_value || @latest_allocation_task.ending_cash, unit: "$", precision: 2) %>, - 组合净值:<%= number_to_currency(@latest_portfolio_snapshot&.portfolio_value || @latest_allocation_task.portfolio_value, unit: "$", precision: 2) %> + Cash: <%= number_to_currency(@latest_portfolio_snapshot&.cash_value || @latest_allocation_task.ending_cash, unit: "$", precision: 2) %>, + Portfolio Value: <%= number_to_currency(@latest_portfolio_snapshot&.portfolio_value || @latest_allocation_task.portfolio_value, unit: "$", precision: 2) %> <% if @latest_allocation_task.allocation_decision.present? %> - ,<%= link_to "查看建议", allocation_decision_path(@latest_allocation_task.allocation_decision), class: "text-link" %> + , <%= link_to "View Recommendation", allocation_decision_path(@latest_allocation_task.allocation_decision), class: "text-link" %> <% end %>

    @@ -190,12 +190,12 @@
时间参数方向变更原因TimeParameterDirectionChangeReason
- - - - - - + + + + + + @@ -218,24 +218,24 @@ <% else %>
-

当前还没有持仓。执行一条配置建议后,持仓会显示在这里。

+

No current holdings. After executing an allocation recommendation, holdings will be displayed here.

<% end %> <% if @recent_trader_trades.any? %>
-

最近交易流水

+

Recent Trade History

资产数量均价现价市值浮盈亏AssetQuantityAvg CostCurrent PriceMarket ValueUnrealized P/L
- - - - - - + + + + + + @@ -262,18 +262,18 @@ - 交易反思报告 + Trading Reflection Report

- 基于最近 30 天的策略、交易、执行记录、组合快照和当前持仓生成一份反思报告,帮助优化交易策略。 + Generate a reflection report based on the last 30 days of strategies, trades, execution records, portfolio snapshots, and current holdings to help optimize trading strategies.

- <%= button_to "生成反思报告", trader_trader_reflections_path(@trader), method: :post, class: "reflection-report__btn reflection-report__btn--primary" %> + <%= button_to "Generate Reflection", trader_trader_reflections_path(@trader), method: :post, class: "reflection-report__btn reflection-report__btn--primary" %>
@@ -284,7 +284,7 @@
- 最近一份报告 + Latest Report
@@ -292,11 +292,11 @@ - <%= @latest_trader_reflection.reflection_period_start %> 至 <%= @latest_trader_reflection.reflection_period_end %> + <%= @latest_trader_reflection.reflection_period_start %> to <%= @latest_trader_reflection.reflection_period_end %>
<%= link_to trader_trader_reflection_path(@trader, @latest_trader_reflection), class: "reflection-preview__report-link" do %> - 查看完整报告 + View Full Report @@ -316,7 +316,7 @@ - 优点 + Strengths
<%= Array(findings["strengths"]).first.presence || "-" %> @@ -330,7 +330,7 @@ - 问题 + Mistakes
<%= Array(findings["mistakes"]).first.presence || "-" %> @@ -344,7 +344,7 @@ - 风险提示 + Risk Warnings
<%= Array(findings["risk_issues"]).first.presence || "-" %> @@ -361,7 +361,7 @@ - 建议调整 + Suggested Adjustments
<%= suggested_adjustments.size %> @@ -375,7 +375,7 @@ - 生成时间:<%= l(@latest_trader_reflection.generated_at, format: :short) if @latest_trader_reflection.generated_at.present? %> + Generated: <%= l(@latest_trader_reflection.generated_at, format: :short) if @latest_trader_reflection.generated_at.present? %>
@@ -387,7 +387,7 @@ - 最近一次反思报告生成失败:<%= @latest_trader_reflection.error_message %> + Last reflection report generation failed: <%= @latest_trader_reflection.error_message %> <% else %> @@ -398,7 +398,7 @@ -

还没有反思报告。先生成一份最近 30 天的报告,帮助优化策略参数。

+

No reflection reports yet. Generate a report for the last 30 days to help optimize strategy parameters.

<% end %> @@ -407,7 +407,7 @@
- <%= link_to "返回列表", traders_path, class: "btn btn-ghost" %> + <%= link_to "Back to List", traders_path, class: "btn btn-ghost" %>
diff --git a/lib/tasks/trader_name_mapping.json b/lib/tasks/trader_name_mapping.json new file mode 100644 index 0000000..b70fb70 --- /dev/null +++ b/lib/tasks/trader_name_mapping.json @@ -0,0 +1,44 @@ +[ + { + "old_name": "沃伦·巴菲特", + "new_name": "Warren Buffett Style", + "description": "Value investing approach focusing on quality companies at fair prices with long-term holding periods", + "risk_level": "conservative" + }, + { + "old_name": "查理·芒格", + "new_name": "Charlie Munger Style", + "description": "Rational value investing with emphasis on patience and disciplined decision-making", + "risk_level": "balanced" + }, + { + "old_name": "疯狂投机者", + "new_name": "Aggressive Speculator", + "description": "High-risk high-reward trading strategy with aggressive position sizing", + "risk_level": "aggressive" + }, + { + "old_name": "乔治·索罗斯", + "new_name": "George Soros Style", + "description": "Global macro approach with opportunistic trading and market trend following", + "risk_level": "aggressive" + }, + { + "old_name": "本杰明·格雷厄姆", + "new_name": "Benjamin Graham Style", + "description": "Classic value investing focusing on margin of safety and fundamental analysis", + "risk_level": "conservative" + }, + { + "old_name": "彼得·林奇", + "new_name": "Peter Lynch Style", + "description": "Growth at reasonable price strategy investing in understandable businesses", + "risk_level": "balanced" + }, + { + "old_name": "雷·达里奥", + "new_name": "Ray Dalio Style", + "description": "All-weather portfolio approach with economic cycle diversification", + "risk_level": "balanced" + } +] diff --git a/lib/tasks/trader_name_mapping_example.json b/lib/tasks/trader_name_mapping_example.json new file mode 100644 index 0000000..033468c --- /dev/null +++ b/lib/tasks/trader_name_mapping_example.json @@ -0,0 +1,20 @@ +[ + { + "old_name": "保守型投资者", + "new_name": "Conservative Growth Fund", + "description": "Focus on capital preservation and steady income with minimal risk exposure", + "risk_level": "conservative" + }, + { + "old_name": "平衡型投资者", + "new_name": "Balanced Growth Portfolio", + "description": "Balance between growth and income with moderate risk tolerance", + "risk_level": "balanced" + }, + { + "old_name": "激进型投资者", + "new_name": "Aggressive Growth Fund", + "description": "Maximize returns through active trading and higher risk tolerance", + "risk_level": "aggressive" + } +] diff --git a/lib/tasks/update_traders.rake b/lib/tasks/update_traders.rake new file mode 100644 index 0000000..0a8bd3c --- /dev/null +++ b/lib/tasks/update_traders.rake @@ -0,0 +1,242 @@ +# frozen_string_literal: true + +namespace :traders do + desc "List all traders with their IDs and current information" + task list: :environment do + puts "=" * 100 + puts "All Traders in Database" + puts "=" * 100 + puts format("%-6s | %-30s | %-15s | %-15s | %-10s | %-10s", + "ID", "Name", "Risk Level", "Status", "Initial Cap", "Current Cap") + puts "-" * 100 + + Trader.all.each do |trader| + puts format("%-6s | %-30s | %-15s | %-15s | $%-9s | $%-9s", + trader.id, + trader.name[0..29], + trader.risk_level, + trader.status, + number_with_delimiter(trader.initial_capital), + number_with_delimiter(trader.current_capital_value)) + end + + puts "=" * 100 + puts "Total: #{Trader.count} traders" + puts "=" * 100 + end + + desc "Update trader by ID (usage: rails traders:update[id]='New Name')" + task :update, [:id] => :environment do |_t, args| + id = args[:id] + new_name = ENV['NAME'] + new_description = ENV['DESCRIPTION'] + new_risk_level = ENV['RISK_LEVEL'] + new_status = ENV['STATUS'] + new_initial_capital = ENV['INITIAL_CAPITAL'] + + unless id + puts "Error: Please provide trader ID" + puts "Usage: rails 'traders:update[1]' NAME='New Name' DESCRIPTION='New description'" + exit 1 + end + + trader = Trader.find_by(id: id) + unless trader + puts "Error: Trader with ID #{id} not found" + exit 1 + end + + puts "Current Trader Information:" + puts " ID: #{trader.id}" + puts " Name: #{trader.name}" + puts " Description: #{trader.description}" + puts " Risk Level: #{trader.risk_level}" + puts " Status: #{trader.status}" + puts " Initial Capital: $#{number_with_delimiter(trader.initial_capital)}" + + updates = {} + updates[:name] = new_name if new_name.present? + updates[:description] = new_description if new_description.present? + updates[:risk_level] = new_risk_level if new_risk_level.present? + updates[:status] = new_status if new_status.present? + updates[:initial_capital] = new_initial_capital.to_f if new_initial_capital.present? + + if updates.empty? + puts "\nNo updates provided. Use environment variables:" + puts " NAME='New Name'" + puts " DESCRIPTION='New description'" + puts " RISK_LEVEL='conservative|balanced|aggressive'" + puts " STATUS='active|inactive'" + puts " INITIAL_CAPITAL='100000'" + exit 0 + end + + if trader.update(updates) + puts "\n✓ Trader updated successfully!" + puts " Updated fields: #{updates.keys.join(', ')}" + else + puts "\n✗ Update failed:" + trader.errors.full_messages.each do |error| + puts " - #{error}" + end + exit 1 + end + end + + desc "Batch rename traders from a mapping (usage: rails traders:batch_rename FILE=path/to/mapping.json)" + task batch_rename: :environment do + file_path = ENV['FILE'] || 'lib/tasks/trader_name_mapping.json' + + unless File.exist?(file_path) + puts "Error: Mapping file not found at #{file_path}" + puts "Please create a JSON file with the following format:" + puts json_example + exit 1 + end + + begin + mapping = JSON.parse(File.read(file_path)) + rescue JSON::ParserError => e + puts "Error: Invalid JSON file - #{e.message}" + exit 1 + end + + puts "=" * 100 + puts "Batch Renaming Traders" + puts "=" * 100 + puts "Mapping file: #{file_path}" + puts "=" * 100 + + success_count = 0 + failed_count = 0 + + mapping.each do |entry| + old_name = entry['old_name'] + new_name = entry['new_name'] + new_description = entry['description'] + new_risk_level = entry['risk_level'] + + trader = Trader.find_by(name: old_name) + + if trader + updates = {} + updates[:name] = new_name if new_name.present? + updates[:description] = new_description if new_description.present? + updates[:risk_level] = new_risk_level if new_risk_level.present? + + if trader.update(updates) + success_count += 1 + puts "✓ Updated: '#{old_name}' -> '#{new_name}'" + else + failed_count += 1 + puts "✗ Failed: '#{old_name}' - #{trader.errors.full_messages.join(', ')}" + end + else + failed_count += 1 + puts "✗ Not found: '#{old_name}'" + end + end + + puts "=" * 100 + puts "Batch rename completed!" + puts " Success: #{success_count}" + puts " Failed: #{failed_count}" + puts "=" * 100 + end + + desc "Generate sample trader name mapping JSON file" + task generate_mapping: :environment do + mapping_file = 'lib/tasks/trader_name_mapping.json' + + mapping = Trader.all.map do |trader| + { + 'old_name' => trader.name, + 'new_name' => '', + 'description' => trader.description || '', + 'risk_level' => trader.risk_level + } + end + + File.write(mapping_file, JSON.pretty_generate(mapping)) + + puts "=" * 100 + puts "Generated mapping file: #{mapping_file}" + puts "=" * 100 + puts "Edit this file with the new names, then run:" + puts " rails traders:batch_rename FILE=#{mapping_file}" + puts "=" * 100 + end + + desc "Reset all trader names to English based on risk level" + task reset_names: :environment do + name_templates = { + 'conservative' => [ + 'Conservative Growth Fund', + 'Steady Income Portfolio', + 'Capital Preservation Fund', + 'Low Risk Strategy', + 'Defensive Investor' + ], + 'balanced' => [ + 'Balanced Growth Fund', + 'Core Satellite Portfolio', + 'Moderate Strategy', + 'Diversified Income Fund', + 'Dynamic Asset Allocator' + ], + 'aggressive' => [ + 'Aggressive Growth Fund', + 'High Momentum Strategy', + 'Opportunistic Portfolio', + 'Growth at Reasonable Price', + 'Tactical Trader Fund' + ] + } + + puts "=" * 100 + puts "Resetting Trader Names to English" + puts "=" * 100 + + success_count = 0 + Trader.all.each do |trader| + names = name_templates[trader.risk_level] || name_templates['balanced'] + new_name = names[trader.id % names.length] + + if trader.update(name: "#{new_name} ##{trader.id}") + success_count += 1 + puts "✓ Updated: #{trader.id} -> '#{trader.name}'" + else + puts "✗ Failed: #{trader.id} - #{trader.errors.full_messages.join(', ')}" + end + end + + puts "=" * 100 + puts "Completed! Updated #{success_count} traders" + puts "=" * 100 + end + + private + + def number_with_delimiter(number) + number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse + end + + def json_example + <<~JSON + [ + { + "old_name": "当前名称1", + "new_name": "New Name 1", + "description": "New description for this trader", + "risk_level": "conservative" + }, + { + "old_name": "当前名称2", + "new_name": "New Name 2", + "description": "New description for this trader", + "risk_level": "balanced" + } + ] + JSON + end +end From b6242e754074b88ce204471e02ef9eb66d3f96ae Mon Sep 17 00:00:00 2001 From: CircleSoar <493943239@qq.com> Date: Fri, 3 Apr 2026 23:10:28 +0800 Subject: [PATCH 2/2] Translate factor definitions and trading signals modules to English - Translate factor_definitions matrix and correlations views - Translate trading_signals controller messages - Translate factor_llm_service LLM prompts to English - Translate related model and service comments - Add rake tasks for regenerating strategies, rebuilding task summaries, and regenerating reflections - Update trader name mapping JSON Co-Authored-By: Claude Opus 4.6 --- app/agents/strategy_agent.rb | 50 ++--- app/agents/trader_reflection_agent.rb | 41 ++-- .../admin/factor_definitions_controller.rb | 28 +-- .../admin/trading_signals_controller.rb | 14 +- app/models/trading_signal.rb | 2 +- app/services/allocation_execution_service.rb | 8 +- app/services/factor_llm_service.rb | 100 ++++----- app/services/signal_generator_service.rb | 10 +- app/services/strategy_generator_service.rb | 12 +- app/services/trader_reflection_service.rb | 43 ++-- .../factor_definitions/correlations.html.erb | 24 +-- .../admin/factor_definitions/matrix.html.erb | 28 +-- lib/tasks/trader_name_mapping.json | 54 +++++ lib/tasks/update_traders.rake | 204 +++++++++++++++++- 14 files changed, 439 insertions(+), 179 deletions(-) diff --git a/app/agents/strategy_agent.rb b/app/agents/strategy_agent.rb index 5e2613e..2106b39 100644 --- a/app/agents/strategy_agent.rb +++ b/app/agents/strategy_agent.rb @@ -4,35 +4,35 @@ class StrategyAgent < RubyLLM::Agent model "gpt-5.2" instructions <<~PROMPT - 你是一位专业的投资顾问。根据投资者的风险偏好和市场环境,生成适合的交易策略参数。 + You are a professional investment advisor. Generate appropriate trading strategy parameters based on the investor's risk preference and market environment. - 市场环境说明: - - normal: 正常市场环境,稳定运行 - - volatile: 高波动市场,价格剧烈波动 - - crash: 崩盘市场,价格大幅下跌 - - bubble: 泡沫市场,价格非理性上涨 + Market Environment Description: + - normal: Normal market conditions, stable operation + - volatile: High volatility market, sharp price fluctuations + - crash: Crash market, significant price decline + - bubble: Bubble market, irrational price increase - 风险偏好说明: - - conservative: 保守型,注重本金安全 - - balanced: 平衡型,平衡风险与收益 - - aggressive: 激进型,追求高收益 + Risk Preference Description: + - conservative: Conservative, focus on capital safety + - balanced: Balanced, balance risk and return + - aggressive: Aggressive, pursue high returns - 请根据给定的风险偏好和市场环境,生成以下参数: - 1. 策略名称(简短描述,如"稳健价值投资策略") - 2. 最大持仓数(10个资产) - 3. 买入信号阈值(0.3-0.7,数值越高越严格) - 4. 单个资产最大仓位(0.3-0.7,即30%-70%) - 5. 最小现金保留比例(0.05-0.4,即5%-40%) - 6. 策略说明(1-2句话,针对当前市场环境) + Based on the given risk preference and market environment, generate the following parameters: + 1. Strategy name (brief description, e.g. "Stable Value Investment Strategy") + 2. Maximum positions (2-5 assets) + 3. Buy signal threshold (0.3-0.7, higher value means stricter filtering) + 4. Maximum position size per asset (0.3-0.7, i.e. 30%-70%) + 5. Minimum cash reserve ratio (0.05-0.4, i.e. 5%-40%) + 6. Strategy description (1-2 sentences, specific to current market environment) - 注意: - - 参数必须在合理范围内 - - 保守型投资者:持仓少、阈值高、仓位小、现金多 - - 激进型投资者:持仓多、阈值低、仓位大、现金少 - - 崩盘时:保守型应防守保本,激进型应逆向买入 - - 泡沫时:保守型应获利了结,激进型可趋势跟随 + Notes: + - Parameters must be within reasonable ranges + - Conservative investors: fewer positions, higher threshold, smaller positions, more cash + - Aggressive investors: more positions, lower threshold, larger positions, less cash + - During crash: conservative should defend capital, aggressive should buy contrarian + - During bubble: conservative should take profits, aggressive can follow trend - 请严格按照以下 JSON 格式返回策略参数,不要添加任何 markdown 标记或其他文字: - {"name":"策略名称","max_positions":3,"buy_signal_threshold":0.5,"max_position_size":0.5,"min_cash_reserve":0.2,"description":"策略说明"} + Please return the strategy parameters in the following JSON format only, without any markdown tags or additional text: + {"name":"Strategy Name","max_positions":3,"buy_signal_threshold":0.5,"max_position_size":0.5,"min_cash_reserve":0.2,"description":"Strategy description"} PROMPT end diff --git a/app/agents/trader_reflection_agent.rb b/app/agents/trader_reflection_agent.rb index d623840..29af371 100644 --- a/app/agents/trader_reflection_agent.rb +++ b/app/agents/trader_reflection_agent.rb @@ -4,40 +4,43 @@ class TraderReflectionAgent < RubyLLM::Agent model "gpt-5.2" instructions <<~PROMPT - 你是一位交易复盘与策略微调助手。请基于给定的 trader、策略、交易记录、执行结果、组合表现和当前持仓,生成一份结构化反思报告。 + You are a trading review and strategy adjustment assistant. Generate a structured reflection report based on the given trader, strategy, trading records, execution results, portfolio performance, and current positions. - 目标: - 1. 总结最近一段时间的表现。 - 2. 识别策略执行中的优点、错误、模式和风险问题。 - 3. 只对有限参数给出微调建议,不要直接改写整套策略。 + IMPORTANT: All output must be in ENGLISH language. - 可建议的参数只有: + Goals: + 1. Summarize performance over the recent period. + 2. Identify strengths, mistakes, patterns, and risk issues in strategy execution. + 3. Provide limited adjustment suggestions for specific parameters only, do not rewrite the entire strategy. + + Suggested parameters are limited to: - max_positions - buy_signal_threshold - max_position_size - min_cash_reserve - 输出要求: - - 必须严格返回 JSON - - 不要输出 markdown 代码块 - - 不要输出解释性前后文 - - 如果你认为无需调整参数,suggested_adjustments 返回空数组 + Output requirements: + - Must return valid JSON only + - Do not output markdown code blocks + - Do not output explanatory context + - If you believe no parameter adjustments are needed, return an empty array for suggested_adjustments + - ALL text values must be in English - 返回格式: + Return format: { - "summary": "string", - "strengths": ["string"], - "mistakes": ["string"], - "pattern_findings": ["string"], - "risk_issues": ["string"], + "summary": "string (in English)", + "strengths": ["string (in English)"], + "mistakes": ["string (in English)"], + "pattern_findings": ["string (in English)"], + "risk_issues": ["string (in English)"], "suggested_adjustments": [ { "parameter": "max_positions|buy_signal_threshold|max_position_size|min_cash_reserve", "direction": "increase|decrease|keep", - "reason": "string" + "reason": "string (in English)" } ], - "recommendation": "string" + "recommendation": "string (in English)" } PROMPT end diff --git a/app/controllers/admin/factor_definitions_controller.rb b/app/controllers/admin/factor_definitions_controller.rb index 6baa1d1..3d9f825 100644 --- a/app/controllers/admin/factor_definitions_controller.rb +++ b/app/controllers/admin/factor_definitions_controller.rb @@ -13,21 +13,21 @@ def index def matrix @factors = FactorDefinition.active.ordered - # 获取最新的因子值,按 asset_id 和 factor_definition_id 分组 + # Get latest factor values, grouped by asset_id and factor_definition_id @factor_values = FactorValue.latest.includes(:asset, :factor_definition) @latest_calculated_at = @factor_values.maximum(:calculated_at) @values_by_asset = @factor_values.group_by(&:asset_id).transform_values do |values| values.index_by { |v| v.factor_definition_id } end - # 获取市值前 50 的资产并计算排序 + # Get top 50 assets by market cap and calculate ranking @assets = sort_assets( Asset.where.not(market_cap_rank: nil).where("market_cap_rank <= 50").to_a, @factors, @values_by_asset ) - # 当前排序参数 + # Current sort parameters @sort_by = params[:sort_by] || "composite" @sort_order = params[:sort_order] || "desc" end @@ -35,16 +35,16 @@ def matrix def correlations @factors = FactorDefinition.active.ordered - # 获取最新的因子值 + # Get latest factor values @factor_values = FactorValue.latest.includes(:factor_definition) - # 按因子分组,得到每个因子在所有资产上的值 + # Group by factor to get each factor's values across all assets @values_by_factor = @factor_values.group_by(&:factor_definition_id) - # 计算因子间相关性矩阵 + # Calculate factor correlation matrix @correlation_matrix = calculate_correlation_matrix(@factors, @values_by_factor) - # 识别高相关性因子对 + # Identify highly correlated factor pairs @high_correlations = find_high_correlations(@factors, @correlation_matrix) end @@ -94,11 +94,11 @@ def calculate_correlation_matrix(factors, values_by_factor) if factor_a.id == factor_b.id matrix[factor_a.id][factor_b.id] = 1.0 else - # 获取两个因子的值序列 + # Get value sequences for both factors values_a = values_by_factor[factor_a.id]&.map(&:normalized_value) || [] values_b = values_by_factor[factor_b.id]&.map(&:normalized_value) || [] - # 计算相关系数 + # Calculate correlation coefficient correlation = calculate_pearson_correlation(values_a, values_b) matrix[factor_a.id][factor_b.id] = correlation end @@ -130,7 +130,7 @@ def find_high_correlations(factors, matrix) factors.each_with_index do |factor_a, i| factors.each_with_index do |factor_b, j| - next if i >= j # 只计算上三角,避免重复 + next if i >= j # Only calculate upper triangle, avoid duplicates correlation = matrix[factor_a.id][factor_b.id] if correlation.abs >= threshold @@ -150,11 +150,11 @@ def sort_assets(assets, factors, values_by_asset) sort_by = params[:sort_by] || "composite" sort_order = params[:sort_order] || "desc" - # 计算每个资产的排序值 + # Calculate ranking score for each asset assets_with_scores = assets.map do |asset| asset_values = values_by_asset[asset.id] || {} - # 计算综合评分 + # Calculate composite score total_score = 0 total_weight = 0 factors.each do |factor| @@ -166,7 +166,7 @@ def sort_assets(assets, factors, values_by_asset) end composite_score = total_weight > 0 ? (total_score / total_weight) : 0 - # 获取指定因子的值 + # Get specified factor's value factor_score = if sort_by != "composite" factor = factors.find { |f| f.id.to_s == sort_by } factor_value = asset_values[factor&.id] @@ -182,7 +182,7 @@ def sort_assets(assets, factors, values_by_asset) } end - # 排序 + # Sort sorted = assets_with_scores.sort_by { |item| item[:score] } sorted = sorted.reverse if sort_order == "desc" diff --git a/app/controllers/admin/trading_signals_controller.rb b/app/controllers/admin/trading_signals_controller.rb index a67c44b..623d555 100644 --- a/app/controllers/admin/trading_signals_controller.rb +++ b/app/controllers/admin/trading_signals_controller.rb @@ -11,16 +11,16 @@ def index .page(params[:page]) .per(20) - # 筛选 + # Filter @signals = @signals.by_signal_type(params[:signal_type]) if params[:signal_type].present? @signals = @signals.where(asset_id: params[:asset_id]) if params[:asset_id].present? - # 获取每个资产的最新信号 + # Get latest signal for each asset @latest_signals = TradingSignal.includes(:asset) .select("DISTINCT ON (asset_id) trading_signals.*") .order("asset_id, generated_at DESC") - # 统计 + # Statistics @stats = { total: TradingSignal.count, buy: TradingSignal.buy_signals.count, @@ -29,7 +29,7 @@ def index high_confidence: TradingSignal.high_confidence.count } - # 获取最新信号日报 + # Get latest signal daily report @latest_report = DailyReport.latest_for_type('signal') end @@ -41,15 +41,15 @@ def generate signal = service.generate_and_save! if signal - redirect_to admin_trading_signal_path(signal), notice: "信号生成成功" + redirect_to admin_trading_signal_path(signal), notice: "Signal generated successfully" else - redirect_to admin_trading_signals_path, alert: "信号生成失败,请检查因子数据" + redirect_to admin_trading_signals_path, alert: "Signal generation failed, please check factor data" end end def generate_all GenerateSignalsJob.perform_later - redirect_to admin_trading_signals_path, notice: "正在后台生成信号,请稍后刷新页面" + redirect_to admin_trading_signals_path, notice: "Signals are being generated in background, please refresh later" end private diff --git a/app/models/trading_signal.rb b/app/models/trading_signal.rb index ef0aba8..4c43b17 100644 --- a/app/models/trading_signal.rb +++ b/app/models/trading_signal.rb @@ -17,7 +17,7 @@ class TradingSignal < ApplicationRecord scope :hold_signals, -> { where(signal_type: "hold") } scope :high_confidence, -> { where("confidence >= ?", 0.7) } - # 获取每个资产的最新信号 + # Get latest signal for each asset def self.latest_for_all_assets select("DISTINCT ON (asset_id) *").order("asset_id, generated_at DESC") end diff --git a/app/services/allocation_execution_service.rb b/app/services/allocation_execution_service.rb index c699b68..b702065 100644 --- a/app/services/allocation_execution_service.rb +++ b/app/services/allocation_execution_service.rb @@ -15,7 +15,7 @@ def call run_on: @run_at.to_date, status: :running, started_at: @run_at, - summary: "开始执行 allocation decision ##{@allocation_decision.id}" + summary: "Starting execution of allocation decision ##{@allocation_decision.id}" ) ActiveRecord::Base.transaction do @@ -61,7 +61,7 @@ def call @task&.update( status: :failed, error_message: e.message, - summary: "执行失败: #{e.message}", + summary: "Execution failed: #{e.message}", completed_at: Time.current ) raise @@ -185,7 +185,7 @@ def deactivate_non_target_positions!(allocations, existing_positions) previous_value: previous_value.to_f, target_value: 0.0, action: "sell", - reason: "资产不在最新 recommendation 目标组合中", + reason: "Asset not in latest recommendation target portfolio", trade_quantity: previous_quantity.to_f, trade_price: price.to_f, trade_amount: previous_value.to_f @@ -229,7 +229,7 @@ def update_position_metrics!(position, quantity:, average_cost:, price:, active: end def build_summary(updates, portfolio_value) - "执行 #{updates.size} 个目标仓位更新,最新组合净值 #{portfolio_value.to_f.round(2)}。" + "Executed #{updates.size} target position updates, latest portfolio value #{portfolio_value.to_f.round(2)}." end def build_execution_payload(strategy, allocations, updates, starting_cash, ending_cash) diff --git a/app/services/factor_llm_service.rb b/app/services/factor_llm_service.rb index 3c8acde..58640a7 100644 --- a/app/services/factor_llm_service.rb +++ b/app/services/factor_llm_service.rb @@ -1,24 +1,24 @@ # frozen_string_literal: true -# LLM 服务 - 复用 AiChatService +# LLM Service - reuse AiChatService class FactorLlmService SYSTEM_PROMPT = <<~PROMPT - 你是 SmartTrader 量化交易系统的 AI 分析师。 - - 你的职责: - - 分析交易因子数据 - - 生成交易信号和投资建议 - - 识别风险和异常 - - 撰写专业分析报告 - - 你的回答应该: - - 专业、准确、有依据 - - 简洁明了,避免冗余 - - 考虑风险因素 - - 基于数据而非猜测 + You are the AI analyst for SmartTrader quantitative trading system. + + Your responsibilities: + - Analyze trading factor data + - Generate trading signals and investment recommendations + - Identify risks and anomalies + - Write professional analysis reports + + Your responses should be: + - Professional, accurate, and well-founded + - Concise and clear, avoid redundancy + - Consider risk factors + - Based on data, not speculation PROMPT - # 普通文本回答 + # Plain text response def self.ask(prompt, instructions: nil) service = AiChatService.new( instructions: instructions || SYSTEM_PROMPT, @@ -28,12 +28,12 @@ def self.ask(prompt, instructions: nil) service.ask(prompt) end - # JSON 格式回答 + # JSON format response def self.ask_json(prompt, instructions: nil) json_instructions = <<~PROMPT #{instructions || SYSTEM_PROMPT} - 重要:你必须返回有效的 JSON 格式,不要包含 markdown 代码块标记,不要包含其他解释文字。 + IMPORTANT: You must return valid JSON format, do not include markdown code block markers, do not include other explanatory text. PROMPT service = AiChatService.new( @@ -46,13 +46,13 @@ def self.ask_json(prompt, instructions: nil) parse_json(response) end - # 因子解读 + # Factor interpretation def self.interpret_factors(asset, factor_values) prompt = build_interpretation_prompt(asset, factor_values) ask(prompt) end - # 生成交易信号 + # Generate trading signal def self.generate_signal(asset, factor_values, strategy = nil) prompt = build_signal_prompt(asset, factor_values, strategy) ask_json(prompt) @@ -77,72 +77,72 @@ def self.parse_json(response) def self.build_interpretation_prompt(asset, factor_values) <<~PROMPT - 你是一位专业的量化分析师。请分析以下资产的因子数据,给出简洁的解读。 + You are a professional quantitative analyst. Please analyze the following asset's factor data and provide a concise interpretation. - 资产信息: - - 名称:#{asset.name} (#{asset.symbol}) + Asset Information: + - Name: #{asset.name} (#{asset.symbol}) - 因子数据: + Factor Data: #{format_factor_values(factor_values)} - 请回答: - 1. 这个资产目前的主要特征是什么?(用1-2句话概括) - 2. 哪些因子表现突出?意味着什么? - 3. 综合来看,这个资产处于什么状态?(强势/弱势/震荡) + Please answer: + 1. What are the main characteristics of this asset currently? (Summarize in 1-2 sentences) + 2. Which factors stand out? What does this mean? + 3. Overall, what state is this asset in? (Strong/Weak/Volatile) - 请用简洁专业的语言回答,不要超过100字。 + Please respond in concise professional language, no more than 100 words. PROMPT end def self.build_signal_prompt(asset, factor_values, strategy) - strategy_info = strategy ? build_strategy_info(strategy) : "使用默认策略参数" + strategy_info = strategy ? build_strategy_info(strategy) : "Using default strategy parameters" <<~PROMPT - 你是一位专业的交易信号分析师。根据以下因子数据,生成交易信号。 + You are a professional trading signal analyst. Generate trading signals based on the following factor data. - ## 策略信息 + ## Strategy Information #{strategy_info} - ## 资产信息 - - 资产:#{asset.name} (#{asset.symbol}) + ## Asset Information + - Asset: #{asset.name} (#{asset.symbol}) - ## 因子数据 + ## Factor Data #{format_factor_values(factor_values)} - ## 任务 - 根据因子数据生成交易信号。 + ## Task + Generate a trading signal based on factor data. - 返回 JSON 格式: + Return JSON format: { "signal_type": "buy|sell|hold", "confidence": 0.0-1.0, - "reasoning": "简要说明信号原因(50字以内)", - "key_factors": ["主要驱动因子1", "主要驱动因子2"], - "risk_warning": "风险提示(如有,可选)" + "reasoning": "Brief explanation of signal reason (within 50 words)", + "key_factors": ["Key driving factor 1", "Key driving factor 2"], + "risk_warning": "Risk warning (if any, optional)" } - 注意: - - 综合考虑所有因子,不要只看单一因子 - - 因子之间可能存在矛盾,需要权衡判断 - - 考虑因子的绝对值和相对变化 + Notes: + - Consider all factors comprehensively, not just a single factor + - Factors may conflict, need to weigh and judge + - Consider both absolute and relative changes of factors PROMPT end def self.build_strategy_info(strategy) <<~INFO - - 策略名称:#{strategy.name} - - 风险偏好:#{strategy.risk_level} - - 买入信号阈值:#{strategy.buy_signal_threshold} - - 最大仓位:#{(strategy.max_position_size * 100).round(0)}% + - Strategy Name: #{strategy.name} + - Risk Level: #{strategy.risk_level} + - Buy Signal Threshold: #{strategy.buy_signal_threshold} + - Max Position Size: #{(strategy.max_position_size * 100).round(0)}% INFO end def self.format_factor_values(factor_values) - return "暂无因子数据" if factor_values.empty? + return "No factor data available" if factor_values.empty? factor_values.map do |fv| factor = fv.factor_definition - "- #{factor.name}: 得分 #{fv.normalized_value.round(2)} (百分位: #{fv.percentile || 'N/A'}%)" + "- #{factor.name}: Score #{fv.normalized_value.round(2)} (Percentile: #{fv.percentile || 'N/A'}%)" end.join("\n") end end diff --git a/app/services/signal_generator_service.rb b/app/services/signal_generator_service.rb index 83da0a1..fba3f48 100644 --- a/app/services/signal_generator_service.rb +++ b/app/services/signal_generator_service.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true -# 信号生成服务 - 调用 LLM 生成交易信号并持久化 +# Signal generation service - calls LLM to generate trading signals and persists them class SignalGeneratorService def initialize(asset, strategy: nil) @asset = asset @strategy = strategy end - # 生成并保存信号 + # Generate and save signal def generate_and_save! signal_data = generate_signal return nil unless signal_data @@ -15,7 +15,7 @@ def generate_and_save! create_trading_signal(signal_data) end - # 仅生成信号(不保存) + # Generate signal only (without saving) def generate_signal factor_values = fetch_factor_values return nil if factor_values.empty? @@ -30,7 +30,7 @@ def generate_signal private def fetch_factor_values - # 获取该资产最新的因子值 + # Get latest factor values for this asset FactorValue.includes(:factor_definition) .where(asset: @asset) .joins(:factor_definition) @@ -41,7 +41,7 @@ def fetch_factor_values def create_trading_signal(signal_data) factor_values = fetch_factor_values - # 构建因子快照 + # Build factor snapshot factor_snapshot = build_factor_snapshot(factor_values) TradingSignal.create!( diff --git a/app/services/strategy_generator_service.rb b/app/services/strategy_generator_service.rb index bd236bf..6a20e89 100644 --- a/app/services/strategy_generator_service.rb +++ b/app/services/strategy_generator_service.rb @@ -40,13 +40,13 @@ def strategy_agent def build_prompt(market_condition) <<~PROMPT - 投资者描述: + Investor Description: "#{@description}" - 风险偏好:#{@risk_level || 'balanced'} - 市场环境:#{market_condition} + Risk Preference: #{@risk_level || 'balanced'} + Market Condition: #{market_condition} - 请返回策略参数。 + Please return the strategy parameters. PROMPT end @@ -73,7 +73,7 @@ def build_strategy_params(data, market_condition) end def sanitize_name(name) - name.to_s.strip[0..99].presence || "AI生成策略" + name.to_s.strip[0..99].presence || "AI Generated Strategy" end def sanitize_risk_level(level) @@ -90,7 +90,7 @@ def sanitize_threshold(value, min_value, max_value) end def sanitize_description(desc) - desc.to_s.strip[0..499].presence || "AI 根据投资风格描述自动生成" + desc.to_s.strip[0..499].presence || "AI auto-generated based on investment style description" end def fallback_strategies diff --git a/app/services/trader_reflection_service.rb b/app/services/trader_reflection_service.rb index 30e0d08..ad95771 100644 --- a/app/services/trader_reflection_service.rb +++ b/app/services/trader_reflection_service.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class TraderReflectionService - PROMPT_VERSION = "v1" + PROMPT_VERSION = "v3_en_strict" def initialize(trader, period_start: 30.days.ago.to_date, period_end: Date.current) @trader = trader @@ -80,29 +80,29 @@ def fallback_report total_profit_loss = metrics["total_profit_loss"].to_d trade_count = metrics["trade_count"].to_i risk_issues = [] - risk_issues << "近期交易次数偏少,样本有限,结论置信度较低。" if trade_count < 3 - risk_issues << "当前持仓浮亏较大,需复核入场时机与仓位控制。" if metrics["unrealized_pnl"].to_d < -1000 + risk_issues << "Recent trading volume is low, sample size is limited, conclusion confidence is low." if trade_count < 3 + risk_issues << "Current positions have significant unrealized loss, need to review entry timing and position control." if metrics["unrealized_pnl"].to_d < -1000 { summary: if total_profit_loss.positive? - "最近一段时间整体仍有盈利,但需要继续复核持仓质量与风险控制。" + "Overall profitable in the recent period, but need to continue reviewing position quality and risk control." elsif total_profit_loss.zero? - "最近一段时间整体接近打平,说明策略尚未形成明显优势。" + "Overall break-even recently, indicating the strategy has not yet established a clear advantage." else - "最近一段时间整体表现偏弱,应优先复核买入门槛、仓位集中度和现金保留比例。" + "Overall performance is weak recently, should prioritize reviewing buy threshold, position concentration, and cash reserve ratio." end, findings: { "strengths" => [ - "当前策略和交易执行链路完整,能够持续产出 recommendation 并落地执行。" + "Current strategy and trading execution pipeline is complete, able to continuously produce recommendations and execute them." ], "mistakes" => [ - "近期表现说明策略参数与市场环境之间可能存在错配。" + "Recent performance indicates possible mismatch between strategy parameters and market conditions." ], "pattern_findings" => [ - "反思结果基于最近 30 天执行记录、交易流水、组合快照和当前持仓。" + "Reflection results are based on execution records, trading history, portfolio snapshots, and current positions from the last 30 days." ], "risk_issues" => risk_issues, - "recommendation" => "建议先阅读反思报告,再决定是否人工微调现有策略参数。" + "recommendation" => "Recommend reading the reflection report first, then decide whether to manually fine-tune existing strategy parameters." }, suggested_adjustments: suggested_adjustments_from_metrics(metrics) } @@ -115,7 +115,7 @@ def suggested_adjustments_from_metrics(metrics) adjustments << { "parameter" => "buy_signal_threshold", "direction" => "increase", - "reason" => "近期持仓浮亏偏大,建议提高买入门槛,减少边际信号质量不足的入场。" + "reason" => "Recent positions have significant unrealized losses, recommend raising buy threshold to reduce entries with marginal signal quality." } end @@ -123,7 +123,7 @@ def suggested_adjustments_from_metrics(metrics) adjustments << { "parameter" => "min_cash_reserve", "direction" => "increase", - "reason" => "当前现金比例偏低,建议提高现金保留,增强回撤期缓冲能力。" + "reason" => "Current cash ratio is low, recommend increasing cash reserve to enhance buffer capacity during drawdowns." } end @@ -132,25 +132,26 @@ def suggested_adjustments_from_metrics(metrics) def prompt <<~PROMPT - 请基于以下 trader 反思上下文,输出 JSON: + Please output JSON in ENGLISH based on the following trader reflection context. + IMPORTANT: All output must be in English language. #{JSON.pretty_generate(reflection_payload)} - 返回格式: + Return format (all values in English): { - "summary": "string", - "strengths": ["string"], - "mistakes": ["string"], - "pattern_findings": ["string"], - "risk_issues": ["string"], + "summary": "string (in English)", + "strengths": ["string (in English)"], + "mistakes": ["string (in English)"], + "pattern_findings": ["string (in English)"], + "risk_issues": ["string (in English)"], "suggested_adjustments": [ { "parameter": "max_positions|buy_signal_threshold|max_position_size|min_cash_reserve", "direction": "increase|decrease|keep", - "reason": "string" + "reason": "string (in English)" } ], - "recommendation": "string" + "recommendation": "string (in English)" } PROMPT end diff --git a/app/views/admin/factor_definitions/correlations.html.erb b/app/views/admin/factor_definitions/correlations.html.erb index f73ec4d..8407540 100644 --- a/app/views/admin/factor_definitions/correlations.html.erb +++ b/app/views/admin/factor_definitions/correlations.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "因子相关性 - SmartTrader" %> +<% content_for :title, "Factor Correlations - SmartTrader" %>
@@ -8,9 +8,9 @@ - 返回列表 + Back to List <% end %> -

因子相关性分析

+

Factor Correlation Analysis

@@ -19,7 +19,7 @@
-

相关性矩阵

+

Correlation Matrix

@@ -70,7 +70,7 @@ - 高相关性警告 (>0.6) + High Correlation Warning (>0.6)
@@ -89,7 +89,7 @@
- 建议降低其中一个因子的权重 + Consider reducing the weight of one factor
<% end %> @@ -104,7 +104,7 @@ - 所有因子相关性均在合理范围内 + All factor correlations are within reasonable range @@ -114,23 +114,23 @@
- 强正相关 (>0.6) + Strong Positive (>0.6)
- 弱正相关 (0.3~0.6) + Weak Positive (0.3~0.6)
- 无相关 (-0.3~0.3) + No Correlation (-0.3~0.3)
- 弱负相关 (-0.6~-0.3) + Weak Negative (-0.6~-0.3)
- 强负相关 (<-0.6) + Strong Negative (<-0.6)
diff --git a/app/views/admin/factor_definitions/matrix.html.erb b/app/views/admin/factor_definitions/matrix.html.erb index 592ebfb..a32e654 100644 --- a/app/views/admin/factor_definitions/matrix.html.erb +++ b/app/views/admin/factor_definitions/matrix.html.erb @@ -1,4 +1,4 @@ -<% content_for :title, "因子矩阵 - SmartTrader" %> +<% content_for :title, "Factor Matrix - SmartTrader" %> <% def sort_link(column, label, current_sort_by, current_sort_order) @@ -23,13 +23,13 @@ - 返回列表 + Back to List <% end %> -

因子矩阵

+

Factor Matrix

- 更新时间: <%= @latest_calculated_at&.strftime('%Y-%m-%d %H:%M') || '暂无数据' %> + Updated: <%= @latest_calculated_at&.strftime('%Y-%m-%d %H:%M') || 'No data' %>
@@ -45,8 +45,8 @@ -

暂无资产数据

-

请先添加资产并采集数据

+

No asset data

+

Please add assets and collect data first

<% elsif @factor_values.empty? %>
@@ -56,16 +56,16 @@
-

暂无因子数据

-

请先运行因子计算任务

- <%= button_to "计算因子", "#", class: "btn btn-primary", disabled: true %> +

No factor data

+

Please run factor calculation tasks first

+ <%= button_to "Calculate Factors", "#", class: "btn btn-primary", disabled: true %> <% else %>
时间动作资产数量价格金额TimeActionAssetQuantityPriceAmount
- + <% @factors.each do |factor| %> <% end %> @@ -128,15 +128,15 @@
- 正分 (> 0.3) + Positive (> 0.3)
- 中性 (-0.3 ~ 0.3) + Neutral (-0.3 ~ 0.3)
- 负分 (< -0.3) + Negative (< -0.3)
<% end %> diff --git a/lib/tasks/trader_name_mapping.json b/lib/tasks/trader_name_mapping.json index b70fb70..cb42b37 100644 --- a/lib/tasks/trader_name_mapping.json +++ b/lib/tasks/trader_name_mapping.json @@ -40,5 +40,59 @@ "new_name": "Ray Dalio Style", "description": "All-weather portfolio approach with economic cycle diversification", "risk_level": "balanced" + }, + { + "old_name": "保守型投资者", + "new_name": "Conservative Investor", + "description": "Focus on capital preservation with stable, low-risk investments", + "risk_level": "conservative" + }, + { + "old_name": "平衡型投资者", + "new_name": "Balanced Investor", + "description": "Balanced approach between risk and return with diversified portfolio", + "risk_level": "balanced" + }, + { + "old_name": "激进型投资者", + "new_name": "Aggressive Investor", + "description": "High-risk strategy seeking maximum returns with active trading", + "risk_level": "aggressive" + }, + { + "old_name": "稳健投资", + "new_name": "Steady Investment Fund", + "description": "Conservative strategy focusing on steady growth and capital preservation", + "risk_level": "conservative" + }, + { + "old_name": "价值投资", + "new_name": "Value Investment Fund", + "description": "Value-oriented strategy seeking undervalued quality companies", + "risk_level": "conservative" + }, + { + "old_name": "成长投资", + "new_name": "Growth Investment Fund", + "description": "Growth-focused strategy investing in high-potential companies", + "risk_level": "aggressive" + }, + { + "old_name": "量化交易", + "new_name": "Quantitative Trading Fund", + "description": "Data-driven strategy using quantitative models for trading decisions", + "risk_level": "balanced" + }, + { + "old_name": "趋势跟踪", + "new_name": "Trend Following Fund", + "description": "Strategy that follows market trends with momentum-based trading", + "risk_level": "aggressive" + }, + { + "old_name": "指数增强", + "new_name": "Enhanced Index Fund", + "description": "Index-tracking strategy with active management for excess returns", + "risk_level": "balanced" } ] diff --git a/lib/tasks/update_traders.rake b/lib/tasks/update_traders.rake index 0a8bd3c..d98e70f 100644 --- a/lib/tasks/update_traders.rake +++ b/lib/tasks/update_traders.rake @@ -125,8 +125,14 @@ namespace :traders do updates[:risk_level] = new_risk_level if new_risk_level.present? if trader.update(updates) + # Regenerate strategies with new English LLM prompts + trader.trading_strategies.destroy_all + service = StrategyGeneratorService.new(trader.description, risk_level: trader.risk_level) + strategies = service.generate_strategies + strategies.each { |params| trader.trading_strategies.create(params) } + success_count += 1 - puts "✓ Updated: '#{old_name}' -> '#{new_name}'" + puts "✓ Updated: '#{old_name}' -> '#{new_name}' (strategies regenerated)" else failed_count += 1 puts "✗ Failed: '#{old_name}' - #{trader.errors.full_messages.join(', ')}" @@ -167,6 +173,202 @@ namespace :traders do puts "=" * 100 end + desc "Regenerate English strategies for all traders (using matrix strategies, already in English)" + task regenerate_strategies: :environment do + puts "=" * 100 + puts "Regenerating English Strategies for All Traders" + puts "=" * 100 + + success_count = 0 + failed_count = 0 + + Trader.all.each do |trader| + # Delete related records first to avoid foreign key issues + reflection_ids = trader.trader_reflections.pluck(:id) + StrategyAdjustmentLog.where(trader_reflection_id: reflection_ids).delete_all + trader.trading_strategies.destroy_all + + # Use matrix strategies directly (already in English) + TradingStrategy.market_conditions.keys.each do |market_condition| + matrix_params = TradingStrategy.strategy_for(trader.risk_level, market_condition) + trader.trading_strategies.create( + name: matrix_params[:name], + risk_level: trader.risk_level, + max_positions: matrix_params[:max_positions], + buy_signal_threshold: matrix_params[:buy_signal_threshold], + max_position_size: matrix_params[:max_position_size], + min_cash_reserve: matrix_params[:min_cash_reserve], + description: matrix_params[:description], + market_condition: market_condition, + generated_by: :matrix + ) + end + + success_count += 1 + puts "✓ Regenerated strategies for: '#{trader.name}' (ID: #{trader.id})" + rescue => e + failed_count += 1 + puts "✗ Failed: '#{trader.name}' (ID: #{trader.id}) - #{e.message}" + end + + puts "=" * 100 + puts "Completed! Regenerated strategies for #{success_count} traders" + puts "Failed: #{failed_count}" + puts "=" * 100 + end + + desc "Rebuild allocation task summaries in English from existing data" + task rebuild_task_summaries: :environment do + puts "=" * 100 + puts "Rebuilding Allocation Task Summaries in English" + puts "=" * 100 + + updated_count = 0 + + AllocationTask.find_each do |task| + # Rebuild summary based on task status and data + if task.status == "completed" + trade_count = task.trader_trades.count + portfolio_value = task.portfolio_value + new_summary = "Executed #{trade_count} position updates, latest portfolio value #{portfolio_value.to_f.round(2)}." + elsif task.status == "failed" + new_summary = "Execution failed: #{task.error_message || 'Unknown error'}" + elsif task.status == "running" + new_summary = "Starting execution of allocation decision ##{task.allocation_decision_id}" + else + new_summary = "Task status: #{task.status}" + end + + if task.summary != new_summary + task.update(summary: new_summary) + updated_count += 1 + puts "✓ Updated task #{task.id}: #{new_summary[0..60]}..." + end + end + + puts "=" * 100 + puts "Rebuilt #{updated_count} task summary(s)" + puts "=" * 100 + end + + desc "Translate allocation task summaries from Chinese to English" + task translate_task_summaries: :environment do + puts "=" * 100 + puts "Translating Allocation Task Summaries" + puts "=" * 100 + + # Common translations + translations = { + "执行" => "Executed", + "个目标仓位更新" => "target position updates", + "最新组合净值" => "latest portfolio value", + "开始执行" => "Starting execution of", + "执行失败" => "Execution failed", + "资产不在最新 recommendation 目标组合中" => "Asset not in latest recommendation target portfolio" + } + + updated_count = 0 + + AllocationTask.where.not(summary: [nil, ""]).find_each do |task| + original_summary = task.summary + translated = original_summary.dup + + # Apply translations + translations.each do |chinese, english| + translated.gsub!(chinese, english) + end + + # Only update if translation actually changed something + if translated != original_summary + task.update(summary: translated) + updated_count += 1 + puts "✓ Updated: #{original_summary[0..50]}... -> #{translated[0..50]}..." + end + end + + puts "=" * 100 + puts "Translated #{updated_count} task summary(s)" + puts "=" * 100 + end + + desc "Clear old allocation task summaries (optional: these are historical records)" + task clear_task_summaries: :environment do + puts "=" * 100 + puts "Clearing Old Allocation Task Summaries" + puts "=" * 100 + + updated_count = AllocationTask.where.not(summary: [nil, ""]).update_all(summary: nil) + + puts "Cleared #{updated_count} task summary(s)" + puts "=" * 100 + puts "Cleared! New tasks will have English summaries" + puts "=" * 100 + end + + desc "Clear all trader reflections (will be regenerated with English prompts)" + task clear_reflections: :environment do + puts "=" * 100 + puts "Clearing All Trader Reflections" + puts "=" * 100 + + # Delete strategy adjustment logs first + reflection_ids = TraderReflection.pluck(:id) + deleted_logs = StrategyAdjustmentLog.where(trader_reflection_id: reflection_ids).delete_all + + # Delete reflections + deleted_count = TraderReflection.delete_all + + puts "Deleted #{deleted_count} reflection(s)" + puts "Deleted #{deleted_logs} strategy adjustment log(s)" + puts "=" * 100 + puts "Cleared! Use 'traders:regenerate_reflections' to regenerate in English" + puts "=" * 100 + end + + desc "Regenerate all trader reflections with English prompts" + task regenerate_reflections: :environment do + puts "=" * 100 + puts "Regenerating Trader Reflections with English Prompts" + puts "=" * 100 + + success_count = 0 + failed_count = 0 + + Trader.all.each do |trader| + period_end = Date.current + period_start = 30.days.ago.to_date + + begin + # Check if reflection already exists + existing = trader.trader_reflections.find_by( + reflection_period_start: period_start, + reflection_period_end: period_end + ) + + if existing + puts "⊘ Skipping: '#{trader.name}' (ID: #{trader.id}) - already exists" + next + end + + service = TraderReflectionService.new(trader, + period_start: period_start, + period_end: period_end + ) + service.call + success_count += 1 + puts "✓ Generated: '#{trader.name}' (ID: #{trader.id})" + rescue => e + failed_count += 1 + puts "✗ Failed: '#{trader.name}' (ID: #{trader.id}) - #{e.message}" + end + end + + puts "=" * 100 + puts "Completed! Generated #{success_count} reflections" + puts "Failed: #{failed_count}" + puts "=" * 100 + end + desc "Reset all trader names to English based on risk level" task reset_names: :environment do name_templates = {
资产Asset <%= sort_link(factor.id.to_s, factor.name, @sort_by, @sort_order) %> @@ -73,7 +73,7 @@ - <%= sort_link("composite", "综合评分", @sort_by, @sort_order) %> + <%= sort_link("composite", "Composite Score", @sort_by, @sort_order) %>