完整流程
多策略組合
本頁內容12
這一頁帶你把幾個風格不同的策略合成一個投資組合:先回測組合績效、調整權重,再用 PortfolioSyncManager 算出實際持股,最後每天自動同步部位並下單。
做完這一頁,你會有:一個合併三個策略的 Portfolio 與它的回測報告、依你的資金算好的持股,以及每天自動更新部位的腳本。
開始前你需要:
為什麼要組合多個策略
| 單一策略的風險 | 多策略組合的好處 |
|---|---|
| 市場環境變化:策略在特定市場環境表現好,但環境改變時可能失效 | 分散風險:不同策略在不同市場環境下互補 |
| 回撤風險:單一策略的最大回撤可能很大 | 降低回撤:組合的最大回撤通常小於單一策略 |
| 收益不穩定:策略可能長時間表現不佳 | 穩定收益:平滑單一策略的波動 |
整個流程如下,績效不滿意就回頭調整權重或策略:
1. 準備三個風格不同的策略
建議組合包含不同風格的策略。這裡建三個:短期的技術面動能、中期的基本面價值、中長期的營收成長。
from finlab import data
from finlab.backtest import sim
# 策略 1: 技術面動能策略(短期)
close = data.get('price:收盤價')
volume = data.get('price:成交股數')
entry1 = (close == close.rolling(20).max()) & (volume > volume.average(20) * 1.5)
exit1 = close < close.average(10)
position1 = entry1.hold_until(exit=exit1, stop_loss=0.08)
report1 = sim(position1, resample='W', name="動能策略", upload=False)
# 策略 2: 基本面價值策略(中期)
pb = data.get('price_earning_ratio:股價淨值比')
roe = data.get('fundamental_features:ROE稅後')
entry2 = (pb < pb.quantile(0.3, axis=1)) & (roe > 0.1)
exit2 = pb > pb.quantile(0.7, axis=1)
position2 = entry2.hold_until(exit=exit2)
report2 = sim(position2, resample='M', name="價值策略", upload=False)
# 策略 3: 營收成長策略(中長期)
rev = data.get('monthly_revenue:當月營收')
rev_ma3 = rev.average(3)
rev_ma12 = rev.average(12)
entry3 = (rev_ma3 / rev_ma12 > 1.15) & (close > close.average(60))
exit3 = rev_ma3 / rev_ma12 < 1.0
position3 = entry3.hold_until(exit=exit3, stop_loss=0.1)
report3 = sim(position3, resample='M', name="營收成長策略", upload=False)
print("策略池建立完成!")
print(f"策略 1 年化報酬: {report1.get_stats()['cagr'] * 100:.2f}%")
print(f"策略 2 年化報酬: {report2.get_stats()['cagr'] * 100:.2f}%")
print(f"策略 3 年化報酬: {report3.get_stats()['cagr'] * 100:.2f}%")以 S&P 500 成分股為範圍:
from finlab import data
from finlab.backtest import sim
data.set_market('us')
with data.us_universe(index='SP500'):
close = data.get('price:adj_close')
volume = data.get('price:volume')
market_value = data.get('etl:us_market_value')
net_income = data.get('us_income_statement:net_income')
equity = data.get('us_balance_sheet:total_stockholders_equity')
rev = data.get('us_income_statement:revenue')
# 策略 1: 技術面動能策略(短期)
entry1 = (close == close.rolling(20).max()) & (volume > volume.average(20) * 1.5)
exit1 = close < close.average(10)
position1 = entry1.hold_until(exit=exit1, stop_loss=0.08)
report1 = sim(position1, resample='W', name="動能策略", upload=False)
# 策略 2: 基本面價值策略(中期)
pb = market_value / equity # 股價淨值比
roe = net_income.rolling(4).sum() / equity # 近四季 ROE
pb_rank = pb[pb > 0].rank(axis=1, pct=True) # 0 = 最便宜,1 = 最貴
entry2 = (pb_rank < 0.3) & (roe > 0.1)
exit2 = pb_rank > 0.7
position2 = entry2.hold_until(exit=exit2)
report2 = sim(position2, resample='M', name="價值策略", upload=False)
# 策略 3: 營收成長策略(中長期)
rev_growth = rev.pct_change(4) # 季營收年增率
entry3 = (rev_growth > 0.15) & (close > close.average(60))
exit3 = rev_growth < 0
position3 = entry3.hold_until(exit=exit3, stop_loss=0.1)
report3 = sim(position3, resample='M', name="營收成長策略", upload=False)
print("策略池建立完成!")
print(f"策略 1 年化報酬: {report1.get_stats()['cagr'] * 100:.2f}%")
print(f"策略 2 年化報酬: {report2.get_stats()['cagr'] * 100:.2f}%")
print(f"策略 3 年化報酬: {report3.get_stats()['cagr'] * 100:.2f}%")策略已經上傳到 FinLab 平台的話,直接從雲端載入,不用重跑:
from finlab.portfolio import create_report_from_cloud
# 從 FinLab 平台載入已上傳的策略
report1 = create_report_from_cloud('我的動能策略')
report2 = create_report_from_cloud('我的價值策略')
report3 = create_report_from_cloud('我的營收成長策略')
print("從雲端載入 3 個策略完成!")2. 用 Portfolio 合併策略
Portfolio 收一個字典:鍵是策略名稱,值是 (回測報告, 權重)。
等權重
最簡單的起點,各佔 1/3:
from finlab.portfolio import Portfolio
# 建立等權重組合(各佔 1/3)
port_equal = Portfolio(
{
'動能策略': (report1, 1 / 3),
'價值策略': (report2, 1 / 3),
'營收成長策略': (report3, 1 / 3),
}
)
# 顯示組合績效
port_equal.display()依夏普率配置
夏普率越高,權重越大。夏普率為負的策略以 0 計,權重為 0、不配置資金:
# 取得各策略夏普率(負值以 0 計,該策略權重為 0,不配置資金)
sharpe1 = max(report1.get_stats()['daily_sharpe'], 0)
sharpe2 = max(report2.get_stats()['daily_sharpe'], 0)
sharpe3 = max(report3.get_stats()['daily_sharpe'], 0)
# 計算權重(夏普率越高權重越大)
total_sharpe = sharpe1 + sharpe2 + sharpe3
w1 = sharpe1 / total_sharpe
w2 = sharpe2 / total_sharpe
w3 = sharpe3 / total_sharpe
print(f"動能策略權重: {w1 * 100:.1f}%")
print(f"價值策略權重: {w2 * 100:.1f}%")
print(f"營收成長策略權重: {w3 * 100:.1f}%")
# 建立夏普率加權組合
port_sharpe = Portfolio(
{
'動能策略': (report1, w1),
'價值策略': (report2, w2),
'營收成長策略': (report3, w3),
}
)
port_sharpe.display()比較組合與單一策略
# 取得組合績效
stats_equal = port_equal.get_stats()
stats_sharpe = port_sharpe.get_stats()
# 與單一策略比較
import pandas as pd
comparison = pd.DataFrame(
{
'動能策略': [
report1.get_stats()['cagr'],
report1.get_stats()['daily_sharpe'],
report1.get_stats()['max_drawdown'],
],
'價值策略': [
report2.get_stats()['cagr'],
report2.get_stats()['daily_sharpe'],
report2.get_stats()['max_drawdown'],
],
'營收成長策略': [
report3.get_stats()['cagr'],
report3.get_stats()['daily_sharpe'],
report3.get_stats()['max_drawdown'],
],
'等權組合': [
stats_equal['cagr'],
stats_equal['daily_sharpe'],
stats_equal['max_drawdown'],
],
'夏普加權組合': [
stats_sharpe['cagr'],
stats_sharpe['daily_sharpe'],
stats_sharpe['max_drawdown'],
],
},
index=['年化報酬率', '夏普率', '最大回撤'],
)
print(comparison)策略之間相關性低時,兩個組合欄位的夏普率會高於單一策略、最大回撤會比較小,這就是分散的效果。
3. 檢查組合的風險與分散度
對組合跑深度分析
Portfolio 本身就是回測報告,單一策略能用的分析都能用。流動性分析(LiquidityAnalysis)只支援台股,美股跳過那一行;各分析的解讀見策略分析模組。
# Portfolio 本身就是回測報告
combined_report = port_sharpe
# 流動性分析
combined_report.run_analysis('LiquidityAnalysis', required_volume=100000)
# MAE/MFE 分析
combined_report.display_mae_mfe_analysis()
# 時期穩定性
combined_report.run_analysis('PeriodStatsAnalysis')
# Alpha/Beta
combined_report.run_analysis('AlphaBetaAnalysis')看持股分散度與策略重疊
# 取得組合的持倉
position_combined = combined_report.position
# 計算平均持股數
avg_holdings = (position_combined > 0).sum(axis=1).mean()
print(f"平均持股數: {avg_holdings:.1f}")
# 計算最大單一持股權重
max_weight = position_combined.max(axis=1).mean()
print(f"平均最大單一持股權重: {max_weight * 100:.1f}%")
# 檢查三個策略的重疊度
pos1 = report1.position.iloc[-1]
pos2 = report2.position.iloc[-1]
pos3 = report3.position.iloc[-1]
overlap_12 = len(set(pos1[pos1 > 0].index) & set(pos2[pos2 > 0].index))
overlap_13 = len(set(pos1[pos1 > 0].index) & set(pos3[pos3 > 0].index))
overlap_23 = len(set(pos2[pos2 > 0].index) & set(pos3[pos3 > 0].index))
print(f"動能 & 價值 重疊股數: {overlap_12}")
print(f"動能 & 營收成長 重疊股數: {overlap_13}")
print(f"價值 & 營收成長 重疊股數: {overlap_23}")4. 依近況調整權重(選用)
固定權重已經能用。想讓權重跟著近期表現或市場環境變動,可以用下面兩種做法。
用過去一年的報酬算最小變異數權重
用各策略過去 252 個交易日(約 1 年)的日報酬算共變異數矩陣,找出讓組合變異數最小的權重,限制權重總和為 1、每個權重介於 0 與 1。需要 scipy:
def optimize_weights(reports, lookback_days=252):
"""
根據過去一年的表現,動態調整權重
Args:
reports: list of Report 物件
lookback_days: 回望天數(預設 252 交易日 ≈ 1 年)
Returns:
dict: 最優權重
"""
import numpy as np
from scipy.optimize import minimize
# 取得過去一年的日報酬率
returns = []
for report in reports:
daily_return = report.daily_creturn.pct_change().iloc[-lookback_days:]
returns.append(daily_return)
returns_df = pd.concat(returns, axis=1).dropna()
# 計算協方差矩陣
cov_matrix = returns_df.cov()
# 最小化變異數(風險平價)
def portfolio_variance(weights):
return np.dot(weights, np.dot(cov_matrix, weights))
# 約束:權重總和 = 1,每個權重 >= 0
constraints = {'type': 'eq', 'fun': lambda w: np.sum(w) - 1}
bounds = tuple((0, 1) for _ in range(len(reports)))
# 初始權重
init_weights = np.array([1 / len(reports)] * len(reports))
# 優化
result = minimize(
portfolio_variance,
init_weights,
method='SLSQP',
bounds=bounds,
constraints=constraints,
)
return result.x
# 計算最優權重
optimal_weights = optimize_weights([report1, report2, report3])
print("最優權重:")
for i, w in enumerate(optimal_weights, 1):
print(f" 策略 {i}: {w * 100:.1f}%")
# 建立最優權重組合
port_optimal = Portfolio(
{
'動能策略': (report1, optimal_weights[0]),
'價值策略': (report2, optimal_weights[1]),
'營收成長策略': (report3, optimal_weights[2]),
}
)
port_optimal.display()依市場環境切換權重
先定義三種環境的權重:多頭加重動能、空頭加重價值、盤整均衡配置:
def adaptive_weights(reports, market_condition='bull'):
"""
根據市場環境調整權重
Args:
reports: list of (name, Report) tuples
market_condition: 'bull', 'bear', 或 'sideways'
Returns:
dict: 調整後權重
"""
if market_condition == 'bull':
# 多頭:增加動能策略權重
return [0.5, 0.25, 0.25]
elif market_condition == 'bear':
# 空頭:增加價值策略權重
return [0.2, 0.5, 0.3]
else: # sideways
# 盤整:均衡配置
return [0.33, 0.33, 0.34]再用大盤和 50 日、200 日均線判斷現在的環境(簡化範例):
from finlab import data
taiex = data.get('benchmark_return:發行量加權股價報酬指數').squeeze()
taiex_ma50 = taiex.rolling(50).mean()
taiex_ma200 = taiex.rolling(200).mean()
if taiex.iloc[-1] > taiex_ma50.iloc[-1] > taiex_ma200.iloc[-1]:
market = 'bull'
print("市場環境:多頭")
elif taiex.iloc[-1] < taiex_ma50.iloc[-1] < taiex_ma200.iloc[-1]:
market = 'bear'
print("市場環境:空頭")
else:
market = 'sideways'
print("市場環境:盤整")from finlab import data
sp500 = data.get('world_index:adj_close')['^GSPC'].dropna()
sp500_ma50 = sp500.rolling(50).mean()
sp500_ma200 = sp500.rolling(200).mean()
if sp500.iloc[-1] > sp500_ma50.iloc[-1] > sp500_ma200.iloc[-1]:
market = 'bull'
print("市場環境:多頭")
elif sp500.iloc[-1] < sp500_ma50.iloc[-1] < sp500_ma200.iloc[-1]:
market = 'bear'
print("市場環境:空頭")
else:
market = 'sideways'
print("市場環境:盤整")最後依環境建立組合:
# 根據市場環境調整權重
adaptive_w = adaptive_weights([report1, report2, report3], market)
port_adaptive = Portfolio(
{
'動能策略': (report1, adaptive_w[0]),
'價值策略': (report2, adaptive_w[1]),
'營收成長策略': (report3, adaptive_w[2]),
}
)5. 算出實際持股並下單
建立 PortfolioSyncManager
PortfolioSyncManager 依組合與你的資金算出每檔股票的持股張數。第一次用時新建;之後從存在雲端或本地的部位接著用:
from finlab.portfolio import PortfolioSyncManager
# 第一次建立
pm = PortfolioSyncManager()
# 或從雲端/本地載入已有的部位
# pm = PortfolioSyncManager.from_cloud()
# pm = PortfolioSyncManager.from_local()依資金更新持股
update 只在換股日才會換股:
# 設定總資金
total_balance = 5000000 # 500 萬
# 更新持股(只在換股日才會換股)
pm.update(port_sharpe, total_balance=total_balance)
# 顯示當前持股
print(pm)print(pm) 會印出估計總值(Estimate value),以及每檔股票的 quantity、price、weight、close_price、volume、來自哪些策略(strategy)與 type。
台股:啟用零股或融資
零股與融資選項只用在台股,美股本來就能一股一股買賣。以下三種呼叫擇一,取代上面的 pm.update();之後每次呼叫(包含第 6 步的每日腳本)也要帶上相同的 odd_lot/margin_trading 選項。
這些選項只在策略重建時生效,通常是到達換股日,或設定 smooth_transition=False 且權重改變時。先執行上面的 pm.update() 再單獨改選項,不會重建未改變的部位;只加 smooth_transition=False 也不會強制重建。
# 零股交易(可買賣零股)
pm.update(port_sharpe, total_balance=total_balance, odd_lot=True)
# 融資交易(可使用融資融券)
pm.update(port_sharpe, total_balance=total_balance, margin_trading=True)
# 組合使用
pm.update(port_sharpe, total_balance=total_balance, odd_lot=True, margin_trading=True)同步部位並下單
用 pm.sync(account) 直接同步部位並下單:
from finlab.online.sinopac_account import SinopacAccount
from finlab.online.order_executor import OrderExecutor
# 設定券商帳戶(需先設定環境變數,請參考實盤下單教學)
account = SinopacAccount()
# 使用 pm.sync 直接同步部位並下單
pm.sync(account)from finlab.online.schwab_account import SchwabAccount
# 從環境變數讀取 SCHWAB_API_KEY、SCHWAB_SECRET 與 SCHWAB_TOKEN_PATH
account = SchwabAccount()
# 使用 pm.sync 直接同步部位並下單
pm.sync(account)其他券商的設定見多策略下單。
6. 每天自動同步
把載入策略、更新部位、存回雲端寫成一個函式,每天用 cron 或排程工具執行。台股例如每天早上 8:30,美股可在開盤(美東時間 9:30)前執行:
# 建立每日執行腳本
def daily_portfolio_sync():
"""
每日執行:
1. 檢查是否為換股日
2. 檢查停損停利
3. 更新持股
"""
from finlab.exceptions import PortfolioError
from finlab.portfolio import PortfolioSyncManager, create_report_from_cloud
# 載入策略
report1 = create_report_from_cloud('動能策略')
report2 = create_report_from_cloud('價值策略')
report3 = create_report_from_cloud('營收成長策略')
# 建立組合
port = Portfolio(
{
'動能策略': (report1, 0.4),
'價值策略': (report2, 0.3),
'營收成長策略': (report3, 0.3),
}
)
# 載入現有部位
pm = PortfolioSyncManager.from_cloud()
# 更新(只在換股日會實際換股)
try:
pm.update(port, total_balance=5000000)
except PortfolioError as error:
print(f"資金不足,本次全部停損停利與部位更新尚未執行:{error}")
# 立即調高 total_balance 並重跑;成功後才儲存或同步。
raise
# 同步至雲端
pm.to_cloud()
# 如需下單,啟用以下程式碼:
# account = SinopacAccount()
# pm.sync(account)
print("每日同步完成!")
# 使用 cron 或排程工具定期執行
# 例如:每天早上 8:30 執行7. 追蹤績效、每季重新評估
監控實盤與目標的差異
# 取得目標部位
target_position = pm.get_position()
# 顯示目標持倉
print(pm.get_total_position())
# 使用 pm.sync 模擬下單,檢查實盤與目標的差異
pm.sync(account, view_only=True)想用真實成交重建淨值、和策略目標逐日比對,見實盤覆盤。
每季重新評估策略權重
移除夏普率低於 0.5 的策略,其餘依夏普率重新分配權重:
# 每季重新評估
def quarterly_rebalance():
"""
每季執行:
1. 重新評估各策略表現
2. 調整權重
3. 移除表現差的策略
4. 新增表現好的策略
"""
# 取得最新 3 個月績效
sharpe1 = report1.get_stats()['daily_sharpe']
sharpe2 = report2.get_stats()['daily_sharpe']
sharpe3 = report3.get_stats()['daily_sharpe']
print(f"動能策略 3M 夏普率: {sharpe1:.2f}")
print(f"價值策略 3M 夏普率: {sharpe2:.2f}")
print(f"營收成長策略 3M 夏普率: {sharpe3:.2f}")
# 移除夏普率 < 0.5 的策略
active_strategies = {}
if sharpe1 >= 0.5:
active_strategies['動能策略'] = (report1, sharpe1)
if sharpe2 >= 0.5:
active_strategies['價值策略'] = (report2, sharpe2)
if sharpe3 >= 0.5:
active_strategies['營收成長策略'] = (report3, sharpe3)
# 重新分配權重
total_sharpe = sum(s for _, s in active_strategies.values())
new_port = Portfolio(
{
name: (report, sharpe / total_sharpe)
for name, (report, sharpe) in active_strategies.items()
}
)
print(f"\n保留 {len(active_strategies)} 個策略,重新調整權重")
return new_port
# 每季執行
new_port = quarterly_rebalance()完整程式碼
從建立策略池到存回雲端,一次跑完:
# =============================================================================
# 多策略組合管理完整範例
# =============================================================================
from finlab import data
from finlab.backtest import sim
from finlab.portfolio import Portfolio, PortfolioSyncManager
# 1. 建立策略池
close = data.get('price:收盤價')
volume = data.get('price:成交股數')
pb = data.get('price_earning_ratio:股價淨值比')
roe = data.get('fundamental_features:ROE稅後')
rev = data.get('monthly_revenue:當月營收')
# 策略 1: 動能
position1 = (
(close == close.rolling(20).max()) & (volume > volume.average(20) * 1.5)
).hold_until(exit=close < close.average(10), stop_loss=0.08)
report1 = sim(position1, resample='W', name="動能策略", upload=False)
# 策略 2: 價值
position2 = ((pb < pb.quantile(0.3, axis=1)) & (roe > 0.1)).hold_until(
exit=pb > pb.quantile(0.7, axis=1)
)
report2 = sim(position2, resample='M', name="價值策略", upload=False)
# 策略 3: 營收成長
rev_momentum = rev.average(3) / rev.average(12)
position3 = ((rev_momentum > 1.15) & (close > close.average(60))).hold_until(
exit=rev_momentum < 1.0, stop_loss=0.1
)
report3 = sim(position3, resample='M', name="營收成長策略", upload=False)
# 2. 建立組合
port = Portfolio(
{
'動能策略': (report1, 0.4),
'價值策略': (report2, 0.3),
'營收成長策略': (report3, 0.3),
}
)
# 3. 評估組合績效
port.display()
print(port.get_stats())
# 4. 實盤執行
pm = PortfolioSyncManager()
pm.update(port, total_balance=5000000)
print(pm)
# 5. 同步至雲端
pm.to_cloud()
print("多策略組合建立完成!")# =============================================================================
# 多策略組合管理完整範例(S&P 500 成分股)
# =============================================================================
from finlab import data
from finlab.backtest import sim
from finlab.portfolio import Portfolio, PortfolioSyncManager
# 1. 建立策略池
data.set_market('us')
with data.us_universe(index='SP500'):
close = data.get('price:adj_close')
volume = data.get('price:volume')
market_value = data.get('etl:us_market_value')
net_income = data.get('us_income_statement:net_income')
equity = data.get('us_balance_sheet:total_stockholders_equity')
rev = data.get('us_income_statement:revenue')
pb = market_value / equity
roe = net_income.rolling(4).sum() / equity
pb_rank = pb[pb > 0].rank(axis=1, pct=True)
# 策略 1: 動能
position1 = (
(close == close.rolling(20).max()) & (volume > volume.average(20) * 1.5)
).hold_until(exit=close < close.average(10), stop_loss=0.08)
report1 = sim(position1, resample='W', name="動能策略", upload=False)
# 策略 2: 價值
position2 = ((pb_rank < 0.3) & (roe > 0.1)).hold_until(exit=pb_rank > 0.7)
report2 = sim(position2, resample='M', name="價值策略", upload=False)
# 策略 3: 營收成長
rev_growth = rev.pct_change(4)
position3 = ((rev_growth > 0.15) & (close > close.average(60))).hold_until(
exit=rev_growth < 0, stop_loss=0.1
)
report3 = sim(position3, resample='M', name="營收成長策略", upload=False)
# 2. 建立組合
port = Portfolio(
{
'動能策略': (report1, 0.4),
'價值策略': (report2, 0.3),
'營收成長策略': (report3, 0.3),
}
)
# 3. 評估組合績效
port.display()
print(port.get_stats())
# 4. 實盤執行
pm = PortfolioSyncManager()
pm.update(port, total_balance=500_000)
print(pm.get_position())
# 5. 同步至雲端
pm.to_cloud()
print("多策略組合建立完成!")檢查清單
| 階段 | 檢查 |
|---|---|
| 建立策略池 | 選擇風格不同的策略(技術面、基本面、籌碼面);策略間相關性低,分散效果好;每個策略都要經過完整回測驗證 |
| 決定權重 | 等權重是最簡單的起點;根據夏普率加權可提升整體風險調整後報酬;定期(每季)重新評估權重 |
| 回測驗證 | 組合的夏普率應高於單一策略;組合的最大回撤應小於單一策略;檢查持股分散度與策略重疊度 |
| 實盤執行 | 使用 PortfolioSyncManager 自動管理部位;定期(每日)同步,確保部位一致;監控實盤與回測的偏差 |
| 持續優化 | 每季重新評估策略表現;移除夏普率 < 0.5 的策略;根據市場環境動態調整權重 |
常見問題
組合多少個策略最好?
建議 3-5 個。太少無法有效分散,太多會稀釋收益且管理複雜。
如何判斷策略是否應該移除?
觀察 3-6 個月的滾動夏普率,若持續 < 0.5 考慮移除。
可以動態增減策略嗎?
可以。使用第 7 步的 quarterly_rebalance() 定期評估,新增表現好的策略,移除表現差的。
多個策略持有同一檔股票時怎麼處理?
PortfolioSyncManager 會自動加總權重。例如策略 A 持有 2330 5%,策略 B 持有 2330 3%,最終組合持有 8%。
如何避免過度交易?
- 使用較長的 resample 週期(M 或 Q)
- 設定最小換股幅度(例如權重變化 < 2% 不調整)
- 優先選擇換股頻率較低的策略
下一步
- 多策略下單 多策略組合的下單細節、權重分配與各券商設定。
- 實盤覆盤 用真實成交重建淨值,和策略目標逐日比對。
- 風險管理 部位上限、停損停利與回撤控制。
- finlab.portfolio API
Portfolio、PortfolioSyncManager的完整參數。
這一頁有幫到你嗎?