Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ GOOGLE_API_KEY=
# Get your API key from: https://siliconflow.cn
# If you obtained your key from https://siliconflow.com, you need to update siliconflow.yaml manually.
SILICONFLOW_API_KEY=
# Locale configuration
LANG=zh-Hans
TIMEZONE=Asia/Shanghai

# Get your API key from: https://platform.openai.com/api-keys
OPENAI_API_KEY=
# Model provider selection
# Supported providers: deepseek, openrouter, siliconflow, google, azure, dashscope, etc.
PRIMARY_PROVIDER=deepseek

# You can set any OpenAI-compatitble API KEY, but you neeed to configure python/configs/providers/openai-compatible.yaml manully.
OPENAI_COMPATIBLE_API_KEY=
OPENAI_COMPATIBLE_BASE_URL=

# Get your API key from: https://bailian.console.aliyun.com/#/home
DASHSCOPE_API_KEY=

SEC_EMAIL=your.name@example.com
# DeepSeek credentials (fill with your actual key)
DEEPSEEK_API_KEY=replace-with-your-deepseek-api-key

# Optional: enable verbose logs during setup
# AGENT_DEBUG_MODE=true
2 changes: 1 addition & 1 deletion README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Discord コミュニティへのご参加をお待ちしています。使用中

## 新規ユーザー向け

最新の ValueCell アプリケーション(MacOS または Windows 用)を GitHub の[リリースページ](https://github.com/ValueCell-ai/valuecell/releases)からダウンロードできます。また、公式ウェブサイト [https://valuecell.ai](https://valuecell.ai) からもダウンロードできます。
最新の ValueCell アプリケーション(MacOS または Windows 用)を GitHub の[リリースページ](https://github.com/ValueCell-ai/valuecell/releases)からダウンロードできます。

インストール後、初回使用時に、お好みのモデルプロバイダーを設定してください。アプリケーション内の指示またはドキュメントを参照してください。

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Welcome to join our Discord community to share feedback and issues you encounter

## New Users

To get started quickly, download the latest ValueCell application for MacOS or Windows from the [Releases page](https://github.com/ValueCell-ai/valuecell/releases) on GitHub. You may also download the application from our official website: [https://valuecell.ai](https://valuecell.ai).
To get started quickly, download the latest ValueCell application for MacOS or Windows from the [Releases page](https://github.com/ValueCell-ai/valuecell/releases) on GitHub.

After installation, please configure your preferred model provider before using ValueCell for the first time. Refer to the instructions in the application or documentation as needed.

Expand Down
2 changes: 1 addition & 1 deletion README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ ValueCell 是一个社区驱动的多智能体金融应用产品,我们的计

## 新用户

要快速开始,请从 GitHub 的[发布页面](https://github.com/ValueCell-ai/valuecell/releases)下载 MacOS 或 Windows 的最新 ValueCell 应用程序。您也可以从我们的官方网站 [https://valuecell.ai](https://valuecell.ai) 下载应用程序。
要快速开始,请从 GitHub 的[发布页面](https://github.com/ValueCell-ai/valuecell/releases)下载 MacOS 或 Windows 的最新 ValueCell 应用程序。

安装后,初次使用 ValueCell 前请配置您首选的模型提供商。请参考应用程序内的说明或文档。

Expand Down
2 changes: 1 addition & 1 deletion README.zh_Hant.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ ValueCell 是一個社群驅動的多智能體金融應用產品,我們的計

## 新使用者

若要快速開始使用,請從 GitHub 的[發布頁面](https://github.com/ValueCell-ai/valuecell/releases)下載適用於 MacOS 或 Windows 的最新 ValueCell 應用程式。您也可以從我們的官方網站 [https://valuecell.ai](https://valuecell.ai) 下載應用程式。
若要快速開始使用,請從 GitHub 的[發布頁面](https://github.com/ValueCell-ai/valuecell/releases)下載適用於 MacOS 或 Windows 的最新 ValueCell 應用程式。

安裝後,使用 ValueCell 前請先設定您偏好的模型供應商。請參閱應用程式內的指示或文件。

Expand Down
16 changes: 7 additions & 9 deletions frontend/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "ValueCell",
"version": "0.1.19",
"version": "0.1.20",
"identifier": "com.valuecell.valuecellapp",
"build": {
"beforeDevCommand": "bun run dev:tauri",
Expand All @@ -10,14 +10,12 @@
"frontendDist": "../build/client"
},
"app": {
"windows": [
{
"title": "ValueCell",
"minWidth": 1300,
"minHeight": 780,
"hiddenTitle": true
}
],
"windows": [{
"title": "ValueCell",
"minWidth": 1300,
"minHeight": 780,
"hiddenTitle": true
}],
"security": {
"csp": null
}
Expand Down
125 changes: 125 additions & 0 deletions frontend/src/api/strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { API_QUERY_KEYS } from "@/constants/api";
import { type ApiResponse, apiClient } from "@/lib/api-client";
import type {
BacktestConfig,
BacktestResult,
CreateStrategy,
ManualClosePositionData,
ManualClosePositionRequest,
MarketStateAndScores,
PortfolioSummary,
Position,
PositionControlUpdate,
Strategy,
StrategyCompose,
StrategyPerformance,
Expand Down Expand Up @@ -97,6 +103,23 @@ export const useCreateStrategy = () => {
});
};

export const useStartStrategy = () => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: (strategyId: string) =>
apiClient.post<ApiResponse<{ message: string }>>(
`/strategies/start?id=${strategyId}`,
),
onSuccess: () => {
// Invalidate strategy list to refetch
queryClient.invalidateQueries({
queryKey: API_QUERY_KEYS.STRATEGY.strategyList,
});
},
});
};

export const useTestConnection = () => {
return useMutation({
mutationFn: (data: CreateStrategy["exchange_config"]) =>
Expand Down Expand Up @@ -163,6 +186,83 @@ export const useCreateStrategyPrompt = () => {
});
};

// Dynamic Strategy APIs
export const useGetMarketStateAndScores = (
symbol?: string,
baseStrategies?: string,
riskMode?: string,
exchangeId?: string,
) => {
return useQuery({
queryKey: API_QUERY_KEYS.STRATEGY.marketStateAndScores([
symbol ?? "",
baseStrategies ?? "",
riskMode ?? "",
exchangeId ?? "",
]),
queryFn: () => {
const params = new URLSearchParams();
if (symbol) params.append("symbol", symbol);
if (baseStrategies) params.append("base_strategies", baseStrategies);
if (riskMode) params.append("risk_mode", riskMode);
if (exchangeId) params.append("exchange_id", exchangeId);

return apiClient.get<ApiResponse<MarketStateAndScores>>(
`/strategies/dynamic/scores?${params.toString()}`,
);
},
select: (data) => data.data,
enabled: !!symbol, // 只有当 symbol 存在时才启用查询
refetchInterval: 30 * 1000, // 每30秒刷新一次
});
};

// Backtest APIs
export const useRunBacktest = () => {
return useMutation({
mutationFn: (config: BacktestConfig) =>
apiClient.post<ApiResponse<{ backtestId: string }>>(
"/strategies/backtest/run",
config,
),
});
};

export const useGetBacktestResult = (backtestId?: string) => {
return useQuery({
queryKey: API_QUERY_KEYS.STRATEGY.backtestResult([backtestId ?? ""]),
queryFn: () =>
apiClient.get<ApiResponse<BacktestResult>>(
`/strategies/backtest/result?id=${backtestId}`,
),
select: (data) => data.data,
enabled: !!backtestId,
refetchInterval: 5 * 1000, // 回测进行中时每5秒刷新
});
};

// Position Control APIs
export const useUpdatePositionControl = () => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: (data: PositionControlUpdate) =>
apiClient.post<ApiResponse<{ message: string }>>(
"/strategies/position-control/update",
data,
),
onSuccess: (_, variables) => {
// 刷新策略列表和持仓信息
queryClient.invalidateQueries({
queryKey: API_QUERY_KEYS.STRATEGY.strategyList,
});
queryClient.invalidateQueries({
queryKey: API_QUERY_KEYS.STRATEGY.strategyHoldings([variables.strategyId]),
});
},
});
};

export const useDeleteStrategyPrompt = () => {
const queryClient = useQueryClient();

Expand Down Expand Up @@ -192,3 +292,28 @@ export const useStrategyPerformance = (strategyId: number | null) => {
enabled: false,
});
};

// Manual Close Position API
export const useManualClosePosition = () => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: (data: ManualClosePositionRequest) =>
apiClient.post<ApiResponse<ManualClosePositionData>>(
"/strategies/close_position",
data,
),
onSuccess: (_, variables) => {
// 刷新策略列表和持仓信息
queryClient.invalidateQueries({
queryKey: API_QUERY_KEYS.STRATEGY.strategyList,
});
queryClient.invalidateQueries({
queryKey: API_QUERY_KEYS.STRATEGY.strategyHoldings([
variables.strategyId,
]),
});
},
});
};

Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ import {
useGetStrategyList,
useGetStrategyPortfolioSummary,
useGetStrategyPriceCurve,
useManualClosePosition,
useStartStrategy,
useStopStrategy,
} from "@/api/strategy";
import CreateStrategyModal from "@/app/agent/components/strategy-items/modals/create-strategy-modal";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import type { AgentViewProps } from "@/types/agent";
import type { Strategy } from "@/types/strategy";
import {
CreateStrategyModal,
MarketStateScores,
PortfolioPositionsGroup,
StrategyComposeList,
TradeStrategyGroup,
Expand Down Expand Up @@ -72,6 +77,38 @@ const StrategyAgentArea: FC<AgentViewProps> = () => {

const { mutateAsync: stopStrategy } = useStopStrategy();
const { mutateAsync: deleteStrategy } = useDeleteStrategy();
const { mutateAsync: closePosition } = useManualClosePosition();
const { mutateAsync: startStrategy } = useStartStrategy();

const handlePositionClose = async (
strategyId: string,
symbol: string,
ratio: number,
) => {
try {
await closePosition({
strategyId,
symbol,
closeRatio: ratio,
});
toast.success(`Successfully closed ${ratio * 100}% of ${symbol} position`);
} catch (error) {
toast.error(
`Failed to close position: ${error instanceof Error ? error.message : "Unknown error"}`,
);
}
};

const handleStrategyRestart = async (strategyId: string) => {
try {
await startStrategy(strategyId);
toast.success("Strategy restarted successfully");
} catch (error) {
toast.error(
`Failed to restart strategy: ${error instanceof Error ? error.message : "Unknown error"}`,
);
}
};

useEffect(() => {
if (strategies.length === 0) {
Expand Down Expand Up @@ -109,6 +146,8 @@ const StrategyAgentArea: FC<AgentViewProps> = () => {
onStrategyDelete={async (strategyId) => {
await deleteStrategy(strategyId);
}}
onPositionClose={handlePositionClose}
onStrategyRestart={handleStrategyRestart}
/>
) : (
<div className="flex flex-1 flex-col items-center justify-center gap-4">
Expand All @@ -132,19 +171,29 @@ const StrategyAgentArea: FC<AgentViewProps> = () => {
</div>

{/* Right section: Trade History and Portfolio/Positions */}
<div className="flex flex-1">
<div className="flex flex-1 overflow-hidden">
{selectedStrategy ? (
<>
<StrategyComposeList
composes={composes}
tradingMode={selectedStrategy.trading_mode}
/>
<PortfolioPositionsGroup
summary={summary}
priceCurve={priceCurve}
positions={positions}
strategy={selectedStrategy}
/>
<div className="flex flex-1 flex-col overflow-y-auto">
{/* 动态策略市场状态 */}
{selectedStrategy.enable_dynamic_strategy && (
<div className="border-b p-6">
<MarketStateScores strategy={selectedStrategy} />
</div>
)}

{/* 持仓和投资组合摘要 */}
<PortfolioPositionsGroup
summary={summary}
priceCurve={priceCurve}
positions={positions}
strategy={selectedStrategy}
/>
</div>
</>
) : (
<div className="flex size-full flex-col items-center justify-center gap-8">
Expand Down
1 change: 1 addition & 0 deletions frontend/src/app/agent/components/strategy-items/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as PortfolioPositionsGroup } from "./portfolio-positions-group";
export { default as StrategyComposeList } from "./strategy-compose-list";
export { default as TradeStrategyGroup } from "./trade-strategy-group";
export { MarketStateScores } from "./market-state-scores";
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ const CreateStrategyModal: FC<CreateStrategyModalProps> = ({
strategy_name: "",
initial_capital: 1000,
max_leverage: 2,
decide_interval: 60,
symbols: TRADING_SYMBOLS,
template_id: prompts.length > 0 ? prompts[0].id : "",
decide_interval: 60, // Default: 60 seconds (1 minute)
},
validators: {
onSubmit: tradingStrategySchema,
Expand Down
Loading
Loading