Tổng hợp các chiến lược tạo tín hiệu giao dịch từ dữ liệu phái sinh VN30F1M (Python)
Chào mọi người, mình muốn chia sẻ một số chiến lược đơn giản để tạo tín hiệu mua/bán (position) trên dữ liệu phái sinh VN30F1M sử dụng Python. Dữ liệu được lấy từ thư viện xnoapi, và có thể backtest trực tiếp bằng hàm Backtest_Derivates. Ngoài ra, bạn cũng có thể sử dụng dữ liệu cơ sở từ thư viện xnoapi, hướng dẫn ở đây https://github.com/xnoproject/xnoapi
Lấy dữ liệu từ xnoapi
from xnoapi import client
from xnoapi.vn.data import derivatives
client(apikey="...")
# Lấy dữ liệu 1 phút của VN30F1M
df = derivatives.get_hist("VN30F1M", "1m")
1. Daily Strategy (Chiến lược theo SMA20 ngày)
- Dựa trên giá đóng cửa hằng ngày so với SMA20.
- Nếu Close > SMA20 → Mua
- Nếu Close < SMA20 → Bán
import pandas as pd
def gen_position(df: pd.DataFrame) -> pd.DataFrame:
df = df.copy()
df['datetime'] = pd.to_datetime(df['Date'] + ' ' + df['time'])
df.set_index('datetime', inplace=True)
daily = df.resample('1D').agg({
'Open': 'first',
'High': 'max',
'Low': 'min',
'Close': 'last',
'volume': 'sum'
}).dropna()
daily['SMA20'] = daily['Close'].rolling(window=20).mean()
daily['daily_position'] = 0
daily.loc[daily['Close'] > daily['SMA20'], 'daily_position'] = 1
daily.loc[daily['Close'] < daily['SMA20'], 'daily_position'] = -1
daily_signals = daily[['daily_position']]
df = df.merge(daily_signals, left_on=df.index.date, right_on=daily_signals.index.date, how='left')
df = df.rename(columns={'daily_position': 'position'}).drop(columns=['key_0'])
return df
df_pos = gen_position(df)
backtest = Backtest_Derivates(df_pos, pnl_type="raw")
backtest.PNL().plot()
2. Normal Strategy (So sánh Close với Median Rolling 20)
import numpy as np
def gen_position(df):
return df.assign(
position=np.sign(df["Close"] - df["Close"].rolling(20).median())
)
3. Simple ML Strategy (Ridge Regression với giá Close)
from sklearn.linear_model import Ridge
def gen_position(df):
model = Ridge()
X = df["Close"].shift(1).fillna(method='bfill').values.reshape(-1, 1)
y = df["Close"].values
model.fit(X, y)
pred = model.predict(X)
df["predicted_close"] = pred
df["position"] = 0
df.loc[pred > df["Close"], "position"] = 1
df.loc[pred < df["Close"], "position"] = -1
return df
df_pos = gen_position(df)
backtest = Backtest_Derivates(df_pos, pnl_type="raw")
backtest.PNL().plot()
4. TA ML Strategy (Kết hợp Moving Average + ML)
from sklearn.linear_model import Ridge
def gen_position(df):
df["ma"] = df["Close"].rolling(window=5).mean().fillna(method='bfill')
model = Ridge()
X = df[["ma"]].shift(1).fillna(method='bfill')
y = df["Close"]
model.fit(X, y)
pred = model.predict(X)
df["predicted_close"] = pred
df["position"] = 0
df.loc[pred > df["Close"], "position"] = -1
df.loc[pred < df["Close"], "position"] = 1
return df
df_pos = gen_position(df)
backtest = Backtest_Derivates(df_pos, pnl_type="raw")
backtest.PNL().plot()
Kết luận
- Các chiến lược trên đều đơn giản và có thể tùy chỉnh thêm các yếu tố như khối lượng, biến động, hoặc tín hiệu đa khung thời gian.
- Chiến lược ML là điểm khởi đầu tốt để phát triển mô hình học sâu hơn (LSTM, Random Forest, XGBoost…).
Backtest_Derivateslà công cụ kiểm tra chiến lược tiện lợi với biểu đồ PnL trực quan.
Nếu anh em có chiến lược nào hay hoặc cần mình triển khai chi tiết thêm chiến lược nâng cao thì cứ comment nhé! ![]()