finlab.online
Live trading module for deploying backtested strategies to real broker accounts with automated order execution.
Important Risk Warning
Live trading involves real money. Errors can lead to financial losses!
Mandatory Safety Principles:
- Always test with a simulated account for at least 1 month first
- Start with no more than 10-20% of total capital
- Monitor positions and order status daily
- Set stop-loss mechanisms to avoid large single losses
- Use separate accounts for development/testing and production environments
- NEVER use all capital on an untested strategy
- NEVER ignore error messages or abnormal states
Use Cases
- Automated trading: Automatically place orders and rebalance based on strategy signals
- Multi-account management: Manage multiple broker accounts simultaneously (SinoPac, Fubon, etc.)
- Live tracking: Record actual trading performance and compare with backtest results
- Risk control: Automatically detect position anomalies, single-stock overweight, insufficient capital, etc.
Transition from Backtesting to Live Trading
graph LR
A[Strategy Backtest] --> B[Out-of-Sample Test]
B --> C[Upload to Cloud]
C --> D[Simulated Account Test]
D --> E{Test Passed?}
E -->|Yes| F[Small Capital Live]
E -->|No| A
F --> G[Gradually Increase Capital]
Recommended Timeline: 1. Strategy backtesting (1-2 weeks): Confirm logic is correct 2. Out-of-sample testing (2-4 weeks): Use unseen data 3. Simulated account (4-8 weeks): Real market conditions, no real money 4. Small capital live (8-12 weeks): 10-20% capital test 5. Gradual expansion (as appropriate): Increase capital only after confirming stability
Quick Examples
Basic Usage: Automated Order Execution
from finlab.online.order_executor import Position, OrderExecutor
from finlab.online.base_account import Account
# 1. Configure broker account (example: SinoPac Securities)
account = Account(
broker='shioaji', # SinoPac Securities
account='YOUR_ACCOUNT_ID', # Account ID
password='YOUR_PASSWORD' # Password (use environment variables recommended)
)
# 2. Create order executor
executor = OrderExecutor(
account=account,
market='TW', # Taiwan stocks
base_currency='TWD' # TWD
)
# 3. Get latest positions from cloud
position = Position.from_report(
report_id='YOUR_REPORT_ID', # Cloud strategy ID
total_funds=1000000 # Total capital 1M TWD
)
# 4. Execute orders (please test on simulated account first!)
executor.create_orders(position)
Detailed Guide
See the following tutorials for the complete workflow:
- Live Trading Tutorial (Single Strategy) - Basic order flow
- Live Trading Tutorial (Multi-Strategy) - Portfolio order management
- Risk Management Guide - Live risk control
- Complete Strategy Development Workflow - From research to live trading
API Reference
Account
finlab.online.base_account.Account
Bases: ABC
module_version
class-attribute
instance-attribute
股票帳戶的 abstract class 可以繼承此 Account,來實做券商的帳戶買賣動作,目前已經實做 SinopacAccount (永豐證券) 以及 FugleAccount (玉山富果),來進行交易。可以用以下方式建構物件並用來交易:
永豐證券
import os
from finlab.online.sinopac_account import SinopacAccount
# 舊版請使用
# shioaji < 1.0.0 and finlab < 0.3.18
os.environ['SHIOAJI_ACCOUNT']= '永豐證券帳號'
os.environ['SHIOAJI_PASSWORD']= '永豐證券密碼'
# 新版請使用
# shioaji >= 1.0.0 and finlab >= 0.3.18
os.environ['SHIOAJI_API_KEY'] = '永豐證券API_KEY'
os.environ['SHIOAJI_SECRET_KEY'] = '永豐證券SECRET_KEY'
os.environ['SHIOAJI_CERT_PERSON_ID']= '身份證字號'
# shioaji
os.environ['SHIOAJI_CERT_PATH']= '永豐證券憑證路徑'
os.environ['SHIOAJI_CERT_PASSWORD'] = '永豐證券憑證密碼' # 預設與身份證字號
acc = SinopacAccount()
cancel_order
abstractmethod
create_order
abstractmethod
create_order(action, stock_id, quantity, price=None, odd_lot=False, market_order=False, best_price_limit=None, order_cond=OrderCondition.CASH)
產生新的委託單
| PARAMETER | DESCRIPTION |
|---|---|
action
|
買賣方向,通常為 'BUY' 或是 'SELL'
TYPE:
|
stock_id
|
股票代號 ex: '2330'
TYPE:
|
quantity
|
委託股票的總數量(張數),允許小數點
TYPE:
|
price
|
股票買賣的價格(限價單)
TYPE:
|
force
|
是否用最差之價格(長跌停)強制成交? 當成交量足夠時,可以比較快成交,然而當成交量低時,容易有大的滑價
TYPE:
|
wait_for_best_price
|
是否用最佳之價格(長跌停),無限時間等待?當今天要出場時,可以開啟等漲停價來購買,當今天要買入時,可以掛跌停價等待買入時機。
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
order id 券商提供的委託單編號 |
get_orders
abstractmethod
拿到現在所有委託單
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Order]
|
所有委託單 id 與委託單資料 Example
|
get_stocks
abstractmethod
拿到現在股票報價
| ATTRIBUTE | DESCRIPTION |
|---|---|
stock_ids |
一次拿取所有股票的報價,ex: ['1101', '2330']
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict
|
報價資料, Example
|
Account Security Best Practices
Use environment variables for sensitive information:
import os
account = Account(
broker='shioaji',
account=os.environ.get('BROKER_ACCOUNT'),
password=os.environ.get('BROKER_PASSWORD')
)
# Never hardcode credentials in source code!
Separate development/production environments:
Position
finlab.online.order_executor.Position
Position(stocks, weights=None, margin_trading=False, short_selling=False, day_trading_long=False, day_trading_short=False)
使用者可以利用 Position 輕鬆建構股票的部位,並且利用 OrderExecuter 將此部位同步於實際的股票帳戶。
建構股票部位
| ATTRIBUTE | DESCRIPTION |
|---|---|
stocks |
TYPE:
|
margin_trading |
做多部位是否使用融資
TYPE:
|
short_selling |
做空部位是否使用融券
TYPE:
|
day_trading_long |
做多部位為當沖先做多
TYPE:
|
day_trading_short |
做空部位為當沖先做空
TYPE:
|
Examples:
設計部位,持有一張和 100 股 1101
output將兩個部位相加
from finlab.online.order_executor import Position
p1 = Position({'1101': 1})
p2 = Position({'2330': 1})
p1 + p2
[
{'stock_id': '1101', 'quantity': 1.0, 'order_condition': <OrderCondition.CASH: 1>},
{'stock_id': '2330', 'quantity': 1.0, 'order_condition': <OrderCondition.CASH: 1>}
]
from_json
classmethod
Load a JSON file from the given path and convert it to a list of positions.
| PARAMETER | DESCRIPTION |
|---|---|
path
|
The path to the JSON file.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
|
None |
from_list
classmethod
利用 dict 建構股票部位
from_report
classmethod
利用回測完的報告 finlab.report.Report 建構股票部位。
| ATTRIBUTE | DESCRIPTION |
|---|---|
report |
回測完的結果報告。
TYPE:
|
fund |
希望部屬的資金。
TYPE:
|
price |
股票代號對應到的價格,若無則使用最近個交易日的收盤價。
TYPE:
|
odd_lot |
是否考慮零股。預設為 False,只使用整張操作。
TYPE:
|
board_lot_size |
一張股票等於幾股。預設為1000,一張等於1000股。
TYPE:
|
allocation |
資產配置演算法選定,預設為
TYPE:
|
margin_trading |
做多部位是否使用融資
TYPE:
|
short_selling |
做空部位是否使用融券
TYPE:
|
day_trading_long |
做多部位為當沖先做多
TYPE:
|
day_trading_short |
做空部位為當沖先做空
TYPE:
|
leverage |
目標槓桿倍數,預設為1.0(不使用融資)。若>1.0,會根據波動度分配融資。
TYPE:
|
Example
from_weight
classmethod
from_weight(weights, fund, price=None, odd_lot=False, board_lot_size=None, allocation=greedy_allocation, precision=None, leverage=1.0, price_history=None, **kwargs)
利用 weight 建構股票部位
| ATTRIBUTE | DESCRIPTION |
|---|---|
weights |
股票詳細部位,股票代號對應權重
TYPE:
|
fund |
資金大小
TYPE:
|
price |
股票代號對應到的價格,若無則使用最近個交易日的收盤價。
TYPE:
|
odd_lot |
是否考慮零股
TYPE:
|
board_lot_size |
一張股票等於幾股
TYPE:
|
allocation |
資產配置演算法選定,預設為
TYPE:
|
precision |
計算張數時的精度,預設為 None 代表依照 board_lot_size 而定,而 1 代表 0.1 張,2 代表 0.01 張,以此類推。
TYPE:
|
leverage |
目標槓桿倍數,預設為1.0(不使用融資)。若>1.0,會根據波動度分配融資。
TYPE:
|
price_history |
股票歷史價格,若 leverage > 1.0 時必須提供。
TYPE:
|
margin_trading |
做多部位是否使用融資
TYPE:
|
short_selling |
做空部位是否使用融券
TYPE:
|
day_trading_long |
做多部位為當沖先做多
TYPE:
|
Examples:
例如,用 100 萬的資金,全部投入,持有 1101 和 2330 各一半:
from finlab.online.order_executor import Position
Position.from_weight({
'1101': 0.5,
'2330': 0.5,
}, fund=1000000)
{'stock_id': '1101', 'quantity': 13, 'order_condition': <OrderCondition.CASH: 1>},
{'stock_id': '2330', 'quantity': 1, 'order_condition': <OrderCondition.CASH: 1>}
]
```
OrderExecutor
finlab.online.order_executor.OrderExecutor
對比實際帳戶與欲部屬的股票部位,進行同步 Arguments: target_position (Position): 想要部屬的股票部位。 account (Account): 目前支援永豐與富果帳戶,請參考 Account 來實做。
create_orders
create_orders(market_order=False, best_price_limit=False, view_only=False, extra_bid_pct=0, progress=1, progress_precision=0, buy_only=False, sell_only=False)
產生委託單,將部位同步成 self.target_position 預設以該商品最後一筆成交價設定為限價來下單
| ATTRIBUTE | DESCRIPTION |
|---|---|
market_order |
以類市價盡量即刻成交:所有買單掛漲停價,所有賣單掛跌停價
TYPE:
|
best_price_limit |
掛芭樂價:所有買單掛跌停價,所有賣單掛漲停價
TYPE:
|
view_only |
預設為 False,會實際下單。若設為 True,不會下單,只會回傳欲執行的委託單資料(dict)
TYPE:
|
extra_bid_pct |
以該百分比值乘以價格進行追價下單,如設定為 0.05 時,將以當前價的 +(-)5% 的限價進買入(賣出),也就是更有機會可以成交,但是成交價格可能不理想; 假如設定為 -0.05 時,將以當前價的 -(+)5% 進行買入賣出,也就是限價單將不會立即成交,然而假如成交後,價格比較理想。參數有效範圍為 -0.1 到 0.1 內。
TYPE:
|
progress |
進度,預設為 1,即全部下單。若設定為 0.5,則只下一半的單。
TYPE:
|
progress_precision |
進度的精度,預設為 0,即只下整數張。若設定為 1,則下到 0.1 張。
TYPE:
|
buy_only |
若設為 True,只下買單
TYPE:
|
sell_only |
若設為 True,只下賣單
TYPE:
|
execute_orders
execute_orders(orders, market_order=False, best_price_limit=False, view_only=False, extra_bid_pct=0, cancel_orders=True, buy_only=False, sell_only=False)
產生委託單,將部位同步成 self.target_position 預設以該商品最後一筆成交價設定為限價來下單
| ATTRIBUTE | DESCRIPTION |
|---|---|
orders |
欲下單的部位,通常是由
TYPE:
|
market_order |
以類市價盡量即刻成交:所有買單掛漲停價,所有賣單掛跌停價
TYPE:
|
best_price_limit |
掛芭樂價:所有買單掛跌停價,所有賣單掛漲停價
TYPE:
|
view_only |
預設為 False,會實際下單。若設為 True,不會下單,只會回傳欲執行的委託單資料(dict)
TYPE:
|
extra_bid_pct |
以該百分比值乘以價格進行追價下單,如設定為 0.05 時,將以當前價的 +(-)5% 的限價進買入(賣出),也就是更有機會可以成交,但是成交價格可能不理想; 假如設定為 -0.05 時,將以當前價的 -(+)5% 進行買入賣出,也就是限價單將不會立即成交,然而假如成交後,價格比較理想。參數有效範圍為 -0.1 到 0.1 內。
TYPE:
|
buy_only |
若設為 True,只下買單
TYPE:
|
sell_only |
若設為 True,只下賣單
TYPE:
|
generate_orders
Generate orders based on the difference between target position and present position.
Returns: orders (dict): Orders to be executed.
Order Execution Best Practices
Intraday orders (use limit orders):
# Avoid slippage by using limit orders
executor.create_orders(
position,
order_type='limit', # Limit order
price_offset=-0.01 # Place order 1% below current price
)
Close-price orders (consistent with backtest):
# Use close price for consistency with backtest results
executor.create_orders(
position,
order_type='market_close' # Market-on-close order
)
Batch orders (large orders):
Common Errors and Risks
1. Not checking disposal stocks
# Wrong: Direct ordering may buy disposal stocks
executor.create_orders(position)
# Correct: Filter out disposal stocks
disposal_stocks = data.get('etl:處置股')
# Remove disposal stocks from position
# position = position[~position.index.isin(disposal_stocks)]
executor.create_orders(position)
2. Exceeding available capital
# Check available capital
available_cash = account.get_balance()
required_cash = position.total_value
if required_cash > available_cash:
print(f"Insufficient capital! Required {required_cash:,.0f}, available {available_cash:,.0f}")
# Adjust position or add capital
else:
executor.create_orders(position)
3. Locked at limit up/down, unable to execute
# Check if near limit up/down
close = data.get('price:收盤價')
limit_up = data.get('price:漲停價')
limit_down = data.get('price:跌停價')
# Filter stocks near limit up/down (e.g., within 2%)
near_limit = (
(close > limit_up * 0.98) | # Near limit up
(close < limit_down * 1.02) # Near limit down
)
position = position[~near_limit]
Order
finlab.online.base_account.Order
dataclass
Order(order_id, stock_id, action, price, quantity, filled_quantity, status, order_condition, time, org_order=None)
Order status
委託單的狀態
| ATTRIBUTE | DESCRIPTION |
|---|---|
order_id |
委託單的 id,與券商 API 所提供的 id 一致
TYPE:
|
stock_id |
股票代號 ex: '2330' (亦可透過 symbol 屬性存取)
TYPE:
|
action |
買賣方向,通常為 'BUY' 或是 'SELL'
TYPE:
|
price |
股票買賣的價格(限價單)
TYPE:
|
quantity |
委託股票的總數量(張數),允許小數點
TYPE:
|
filled_quantity |
以成交股票的數量(張數),允許小數點
TYPE:
|
status |
委託狀態,可以設定為:'NEW', 'PARTIALLY_FILLED', 'FILLED', 'CANCEL'
TYPE:
|
time |
委託時間
TYPE:
|
org_order |
券商所提供的委託物件格式
TYPE:
|
order_panel()
finlab.online.panel.order_panel
下單 GUI 介面 Arguments: account (Account): 請參考 Account 針對不同券商來建構相對應的操作帳戶
FAQ
Q: How do I ensure order safety?
Implement the following safety checks:
def safe_order_check(position, account, max_stocks=50, max_weight=0.15):
"""Pre-order safety check"""
# 1. Check position count
if len(position) > max_stocks:
raise ValueError(f"Too many positions ({len(position)}), exceeds limit of {max_stocks}")
# 2. Check single stock weight
max_stock_weight = position.max()
if max_stock_weight > max_weight:
raise ValueError(f"Single stock weight too high ({max_stock_weight:.1%}), exceeds limit of {max_weight:.0%}")
# 3. Check available capital
available = account.get_balance()
required = position.total_value
if required > available * 1.1: # 10% buffer
raise ValueError(f"Insufficient capital! Required {required:,.0f}, available {available:,.0f}")
print("Safety check passed")
return True
# Usage
if safe_order_check(position, account):
executor.create_orders(position)
Q: What if live performance differs from backtest?
Common causes:
- Slippage: Actual execution price differs from expected
-
Solution: Use limit orders or adjust
price_offset -
Insufficient volume: Cannot fully execute
-
Solution: Use LiquidityAnalysis to check beforehand
-
Timing differences: Backtest assumes instant execution
- Solution: Set reasonable order timing (e.g., 30 minutes before close)
Q: How do I set up automatic trading schedules?
import schedule
import time
def auto_trade():
"""Daily automatic trading"""
try:
# 1. Get latest strategy
position = Position.from_report(
report_id='YOUR_REPORT_ID',
total_funds=1000000
)
# 2. Safety check
if safe_order_check(position, account):
# 3. Execute orders
executor.create_orders(position)
print(f"Order completed: {time.strftime('%Y-%m-%d %H:%M:%S')}")
except Exception as e:
# 4. Error notification (LINE/Email)
print(f"Order failed: {e}")
# line_notify(f"Order failed: {e}")
# Execute daily at 14:30 (30 minutes before close)
schedule.every().day.at("14:30").do(auto_trade)
while True:
schedule.run_pending()
time.sleep(60)
Q: How do I handle order failures?
try:
executor.create_orders(position)
print("Order successful")
except Exception as e:
print(f"Order failed: {e}")
# Log error
with open('order_errors.log', 'a') as f:
f.write(f"{time.strftime('%Y-%m-%d %H:%M:%S')} - {e}\n")
# Send notification
# line_notify(f"Order failed: {e}")
# Decide whether to retry based on error type
if "network" in str(e).lower():
time.sleep(30) # Network issue, retry after 30 seconds
executor.create_orders(position)
Resources
- Live Trading Tutorial (Single Strategy) - Detailed steps
- Live Trading Tutorial (Multi-Strategy) - Portfolio management
- Risk Management Guide - Risk control
- Complete Strategy Development Workflow - Full workflow
- GitHub Source Code
Final Reminder
Always test thoroughly on a simulated account before using real capital!
Recommended Test Checklist: - Order workflow executes without errors - Position calculations are correct (match expectations) - Capital control is normal (no overspending) - Error handling mechanisms work - Notification mechanisms function properly - Runs continuously for 1 month without issues
Only consider using real capital after all items above are confirmed!