Trong bài viết này, chúng ta đi vào thực hành: kết nối API chứng khoán Việt Nam (TCBS, DNSE), lấy dữ liệu giá real-time và gửi lệnh giao dịch tự động bằng Python.
Chuẩn Bị Môi Trường
pip install requests pandas numpy python-dotenv
Tạo file .env để lưu credentials an toàn — không bao giờ hard-code token trong code:
TCBS_TOKEN=your_token_here
DNSE_USERNAME=your_email
DNSE_PASSWORD=your_password
1. Lấy Dữ Liệu Giá Với TCBS API
Dữ Liệu Lịch Sử OHLCV
import requests
import pandas as pd
from datetime import datetime, timedelta
def get_historical_data(symbol: str, days: int = 365) -> pd.DataFrame:
to_date = int(datetime.now().timestamp())
from_date = int((datetime.now() - timedelta(days=days)).timestamp())
url = (
f"https://apipubaws.tcbs.com.vn/stock-insight/v1/stock/bars-long-term"
f"?ticker={symbol}&type=stock&resolution=D"
f"&from={from_date}&to={to_date}"
)
response = requests.get(url, timeout=10)
data = response.json()
df = pd.DataFrame(data['data'])
df['date'] = pd.to_datetime(df['tradingDate'])
return df.set_index('date').sort_index()
df_vnm = get_historical_data('VNM', days=365)
print(df_vnm.tail())
Giá Real-time
def get_realtime_price(symbol: str) -> dict:
url = f"https://apipubaws.tcbs.com.vn/stock-insight/v1/stock/quotes?symbol={symbol}"
r = requests.get(url).json()
return {
'symbol': symbol,
'price': r['data'][0]['closePrice'],
'volume': r['data'][0]['totalVolume'],
'change_pct': r['data'][0]['priceChange']
}
2. Đặt Lệnh Với DNSE API
DNSE cung cấp API đặt lệnh chính thức. Sau khi đăng ký và được cấp API access:
class DNSETrader:
BASE_URL = "https://api.dnse.com.vn/v2"
def __init__(self, access_token: str):
self.headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
def place_order(self, symbol: str, side: str, quantity: int,
price: float, order_type: str = "LO") -> dict:
payload = {
"symbol": symbol,
"side": side.upper(),
"quantity": quantity,
"price": price,
"orderType": order_type
}
r = requests.post(f"{self.BASE_URL}/orders",
json=payload, headers=self.headers)
return r.json()
3. Bot MA Crossover Tự Động Hoàn Chỉnh
import time
def is_trading_hours() -> bool:
now = datetime.now()
t = now.hour * 60 + now.minute
morning = 9*60 <= t <= 11*60+30
afternoon = 13*60 <= t <= 14*60+45
return (morning or afternoon) and now.weekday() < 5
def run_bot(symbol: str, trader: DNSETrader):
position = 0
while True:
if not is_trading_hours():
time.sleep(60)
continue
df = get_historical_data(symbol, days=60)
df['ema9'] = df['close'].ewm(span=9).mean()
df['ema21'] = df['close'].ewm(span=21).mean()
cross_up = (df['ema9'].iloc[-1] > df['ema21'].iloc[-1] and
df['ema9'].iloc[-2] < df['ema21'].iloc[-2])
cross_down = (df['ema9'].iloc[-1] < df['ema21'].iloc[-1] and
df['ema9'].iloc[-2] > df['ema21'].iloc[-2])
price = get_realtime_price(symbol)['price']
if cross_up and position == 0:
trader.place_order(symbol, 'buy', 100, price)
position = 1
print(f"BUY {symbol} @ {price}")
elif cross_down and position == 1:
trader.place_order(symbol, 'sell', 100, price)
position = 0
print(f"SELL {symbol} @ {price}")
time.sleep(60)
Lưu Ý Bảo Mật Quan Trọng
- Không push file chứa credentials lên GitHub
- Dùng
.gitignoređể loại trừ.env - Giới hạn quyền API key — chỉ cấp quyền tối thiểu cần thiết
- Monitor bot 24/7 và đặt cảnh báo Telegram khi có lệnh bất thường
Học kỹ hơn về lập trình bot chứng khoán thực chiến tại Hướng Nghiệp Dữ Liệu.
Câu hỏi thường gặp
Làm sao lấy token TCBS hoặc DNSE cho bot Python?
Cả hai đều dùng luồng xác thực qua OTP hoặc mật khẩu để đổi lấy access token, sau đó dùng refresh token để gia hạn. Vì token có thời hạn, code phải lưu refresh token an toàn và tự động lấy token mới, nếu không bot sẽ chết giữa phiên giao dịch.
Có thể test bot chứng khoán mà không rủi ro tiền thật không?
Hầu hết công ty chứng khoán cung cấp môi trường sandbox hoặc tài khoản demo cho API, nhưng tính năng có thể hạn chế hơn bản thật. Cách an toàn nhất là chạy bot ở chế độ chỉ ghi log tín hiệu trong vài tuần để so sánh với dữ liệu thực tế trước khi bật đặt lệnh.
Bot chứng khoán Việt Nam nên chạy trên máy nào?
Nên chạy trên VPS hoặc server đám mây vì phiên giao dịch cố định 9h-15h, máy cá nhân dễ bị ngắt do mất điện hoặc mất mạng đúng lúc cần đặt lệnh. Cấu hình máy thấp cũng đủ vì bot chứng khoán không cần tốc độ mili giây như crypto.
