Tự doanh chứng khoán là hoạt động mà các công ty chứng khoán sử dụng nguồn vốn của chính mình để mua bán các loại chứng khoán trên thị trường. Hiểu một cách đơn giản, khi thực hiện tự doanh, công ty chứng khoán đóng vai trò như một nhà đầu tư độc lập, giao dịch để kiếm lợi nhuận từ chênh lệch giá, giống như một nhà đầu tư cá nhân hay tổ chức khác.
"Khối ngoại" là một thuật ngữ phổ biến trong thị trường chứng khoán Việt Nam, dùng để chỉ các nhà đầu tư nước ngoài. Đây có thể là các cá nhân, quỹ đầu tư, hay các tổ chức tài chính quốc tế tham gia mua bán chứng khoán trên thị trường Việt Nam.
Rất nhiều nhà đầu tư kể cả chuyên nghiệp hay F0 thường nhìn vào hoạt động mua bán của tự doanh, khối ngoại và phân tích, trong bài viết này chúng ta hãy định lượng xem liệu khối ngoại hay tự doanh giao dịch có hiệu quả hay không
Dữ liệu lịch sử mua bán của tự doanh được thu thập thông qua API trên cafef. Ví dụ về API dữ liệu giao dịch tự doanh của mã cổ phiếu SSI như sau
https://cafef.vn/du-lieu/Ajax/PageNew/DataHistory/GDTuDoanh.ashx?Symbol=SSI&StartDate=11/01/2022&EndDate=08/02/2025&PageIndex=1&PageSize=1000
HOSE chính thức công bố dữ liệu giao dịch của tự doanh từ ngày 17/5/2022, Hầu hết các trang về dữ liệu chứng khoán chỉ cho phép nhìn dữ liệu trong ngày, chúng tôi tìm thấy duy nhất cafef thống kê từ 1/11/2022. Vậy nên chúng tôi sẽ định lượng hiệu quả đầu tư của tự doanh từ 1/11/2022
Còn về dữ liệu lịch sử giao dịch khối ngoại có rất nhiều bên cung cấp, chúng tôi sẽ lấy trực tiếp từ bảng giá SSI. Ví dụ về API lấy dữ liệu lịch sử giao dịch khối ngoại của mã cổ phiếu SSI như sau
https://iboard-api.ssi.com.vn/statistics/company/ssmi/stock-info?symbol=ACB&page=1&pageSize=1000&fromDate=01/01/2018&toDate=01/08/2025
API trên trả về rất nhiều thông tin khác như giá và lượng đặt mua bán trong từng phiên, và có dữ liệu chúng ta cần để định lượng hiệu suất của khối ngoại
Về phương pháp định lượng, chúng ta không có thông tin về lượng cổ phiếu mà khối ngoại, tự doanh đang nắm trước khi có dữ liệu. Vậy nên chúng tôi sẽ giả sử lượng cổ phiếu ban đầu họ nắm bằng 0, khi đó phần lợi nhuận thống kê sẽ so sánh với hiệu suất nếu họ chỉ nắm giữ cổ phiếu mà ko có giao dịch nào trong suốt thời gian thống kê. Từ "lợi nhuận" trong bài viết này sẽ chỉ lợi nhuận đầu tư của tự doanh, khối ngoại trừ đi lợi nhuận nếu họ nắm giữ và không có bất kì lệnh nào kể từ thời gian thống kê
Dữ liệu giao dịch của tự doanh được crawl về trên cafef bằng thư viện requests, dữ liệu không có giá đóng cửa từng phiên, và giá mua, giá bán có thể tính bằng GtMua / KLcpMua
thực tế là giá chưa điều chỉnh (khi cổ phiếu chia cổ tức hoặc phát hành thêm thì giá sẽ bị điều chỉnh xuống). Vậy nên dùng thêm dữ liệu bên SSI để có thêm các dữ liệu về giá
import requests
from datetime import datetime
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36'}
now = datetime.now()
tudoanh_data_url = 'https://cafef.vn/du-lieu/Ajax/PageNew/DataHistory/GDTuDoanh.ashx?Symbol={}&StartDate=11/01/2022&EndDate={}&PageIndex=1&PageSize=1000'
price_data_url = 'https://iboard-api.ssi.com.vn/statistics/company/ssmi/stock-info?symbol={}&page=1&pageSize=1000&fromDate=01/11/2022&toDate={}'
list_symbol_url = 'https://iboard-query.ssi.com.vn/stock/exchange/hose?boardId=MAIN'
Đoạn code sau là hàm crawl dữ liệu và lọc ra các dữ liệu cần thiết để làm thống kê, chúng tôi sẽ lọc ra các dữ liệu khối lượng tự doanh mua, bán, giá trị tự doanh mua bán và giá đóng cửa, giá đóng cửa điều chỉnh
data = {}; total_val = {}
def get_data(symbol):
data[symbol] = {}
tudoanh_data_res = requests.get(tudoanh_data_url.format(symbol, now.strftime('%m/%d/%Y')), headers=headers).json()
price_data_res = requests.get(price_data_url.format(symbol, now.strftime('%d/%m/%Y')), headers=headers).json()
total_val[symbol] = (tudoanh_data_res['Data']['Data']['TongGtMua'] + tudoanh_data_res['Data']['Data']['TongGtBan']) / 1e9
for row in tudoanh_data_res['Data']['Data']['ListDataTudoanh']:
date = row['Date']
data[symbol][date] = {'BuyVolume': row['KLcpMua'], 'SellVolume': row['KlcpBan'], 'BuyValue': row['GtMua'], 'SellValue': row['GtBan']}
for row in price_data_res['data']:
date = row['tradingDate']
if date not in data[symbol]:
data[symbol][date] = {}
data[symbol][date]['ClosePrice'] = row['close']
data[symbol][date]['ClosePriceAdjusted'] = row['closePriceAdjusted']
for symbol in list_symbol:
print(symbol)
get_data(symbol)
Sau đó lấy danh sách tất cả các mã cổ phiếu tại sàn HOSE vào mảng list_symbol
và crawl data của tất cả các mã đó như sau:
list_symbol_res = requests.get(list_symbol_url, headers=headers).json()['data']
list_symbol = [r['stockSymbol'] for r in list_symbol_res]
for symbol in list_symbol:
get_data(symbol)
Top 20 cổ phiếu được tự doanh giao dịch nhiều nhất
import matplotlib.pyplot as plt
total_val_sorted = {k: v for k, v in sorted(total_val.items(), key=lambda item: item[1], reverse=True)}
symbols = [k for k in total_val_sorted][:20]
values = [total_val_sorted[k] for k in symbols]
plt.figure(figsize=(16, 4))
plt.bar(symbols, values)
plt.show()
Ở phần này chúng tôi sẽ định lượng hiệu quả vào lệnh của tự doanh. Giả sử trước ngày thống kê họ không nắm giữ bất kì vị thế nào. Khi họ mua chúng tôi sẽ xem như một lệnh LONG và khi bán là một lệnh SHORT, khối lượng sẽ được điều chỉnh khi giá đóng cửa điều chỉnh, để giá trị mua bán của họ là không đổi. Kết quả thu được là lợi nhuận đầu tư của tự doanh, khối ngoại trừ đi lợi nhuận nếu họ nắm giữ và không có bất kì lệnh nào kể từ thời gian thống kê
Vì thống kê chúng tôi giả sử không có phí lưu ký qua đêm, nên lợi nhuận có thể tính bằng cách giả sử các lệnh LONG và SHORT sẽ tồn tại song song, lợi nhuận sau mỗi phiên bằng tổng lợi nhuận của các lệnh LONG cộng với lợi nhuận của các lệnh SHORT trước đó (thực tế chỉ tồn tại một lệnh LONG hoặc SHORT trong một thời điểm, cách tính đó có phần lợi nhuận đã chốt, phần lợi nhuận đó cũng bằng phần lợi nhuận của hai lệnh LONG và SHORT cùng lượng bằng khối lượng đã chốt tại một mức giá bất kì. Ví dụ 1 lệnh LONG 1000 cổ phiếu tại mức giá 25,000 và lệnh SHORT 1000 cổ phiếu tại mức giá 26,000, khi chốt lệnh thì lợi nhuận sẽ là 1,000,000. Còn giả sử hai lệnh tồn tại song song, tại mức giá bất kì ví dụ 27,000 lệnh LONG sẽ lãi 2,000,000, lệnh SHORT sẽ lỗ 1,000,000. Tổng lợi nhuận vẫn bằng 1,000,000). Vậy nên lợi nhuận từng ngày của cổ phiếu symbol
sẽ được tính đơn giản như sau
def compute_profit(symbol):
list_date = [k for k in data[symbol]]
list_date.reverse()
mdata = data[symbol]
total_buy_volume = 0; total_buy_value = 0
total_sell_volume = 0; total_sell_value = 0
all_profit = []
for date in list_date:
if 'ClosePriceAdjusted' in mdata[date]:
rate = float(mdata[date]['ClosePriceAdjusted']) / float(mdata[date]['ClosePrice'])
else: # Có thể du dữ liệu bị lỗi, hoặc tự doanh mua bán thỏa thuận một lượng không đáng kể, có thể bỏ qua
continue
if 'BuyVolume' in mdata[date]:
buy_volume_adjusted = mdata[date]['BuyVolume'] / rate
else:
buy_volume_adjusted = 0
if 'SellVolume' in mdata[date]:
sell_volume_adjusted = mdata[date]['SellVolume'] / rate
else:
sell_volume_adjusted = 0
total_buy_volume += buy_volume_adjusted
total_sell_volume += sell_volume_adjusted
if 'BuyValue' in mdata[date]:
total_buy_value += mdata[date]['BuyValue']
if 'SellValue' in mdata[date]:
total_sell_value += mdata[date]['SellValue']
profit = (float(mdata[date]['ClosePriceAdjusted']) * total_buy_volume - total_buy_value) + (total_sell_value - float(mdata[date]['ClosePriceAdjusted']) * total_sell_volume)
all_profit.append(profit / 1e9)
return list_date, all_profit
Kết quả lợi nhuận đầu tư của tự doanh với một vài mã cổ phiếu như sau, trục y là lợi nhuận (đơn vị: tỷ đồng), trục x là số ngày kể từ ngày bắt đầu thống kê 1/11/2022
Chúng ta sẽ tính toán lợi nhuận đầu tư của tự doanh cho tất cả các cổ phiếu
profit_lastday = {}
for symbol in list_symbol:
_, all_profit = compute_profit(symbol)
profit_lastday[symbol] = all_profit[-1]
sum([profit_lastday[k] for k in profit_lastday])
Kết quả in ra là -49107.07, Vậy tự doanh các công ty chứng khoán đã mất gần 50,000 tỷ so với trường hợp giữ nguyên danh mục kể từ ngày 1/11/2022 đến ngày chúng tôi làm thống kê là 1/8/2025, chúng ta hãy cùng xem những cổ phiếu mà tự doanh lãi và lỗ nhiều nhất
Chúng ta có thể thấy các cổ phiếu tự doanh có lãi nhiều nhất là VIX, GEX, GEE với lợi nhuận tầm 1000 tỷ. Các cổ phiếu mà tự doanh mất nhiều nhất là MSN lỗ gần 13,000 tỷ, VPB gần 10,000 tỷ khi so sánh với trường hợp họ giữ nguyên vị thế từ 1/11/2022
Dữ liệu giao dịch khối ngoại được crawl từ ssi iboard qua thư viện requests, chúng ta sẽ xử lý dữ liệu về một format như dữ liệu tự doanh để sử dụng hàm tính lợi nhuận từ mục 1 như sau
data = {}
def get_data(symbol):
data[symbol] = {}
data_res = requests.get(data_url.format(symbol, now.strftime('%d/%m/%Y')), headers=headers).json()
for row in data_res['data']:
date = row['tradingDate']
data[symbol][date] = {}
data[symbol][date]['ClosePrice'] = float(row['close'])
data[symbol][date]['ClosePriceAdjusted'] = float(row['closePriceAdjusted'])
if row['foreignBuyVolTotal'] != None:
data[symbol][date]['BuyVolume'] = float(row['foreignBuyVolTotal'])
else:
data[symbol][date]['BuyVolume'] = 0
if row['foreignSellVolTotal'] != None:
data[symbol][date]['SellVolume'] = float(row['foreignSellVolTotal'])
else:
data[symbol][date]['SellVolume'] = 0
if row['foreignBuyValTotal'] != None:
data[symbol][date]['BuyValue'] = float(row['foreignBuyValTotal'])
else:
data[symbol][date]['BuyValue'] = 0
if row['foreignSellValTotal'] != None:
data[symbol][date]['SellValue'] = float(row['foreignSellValTotal'])
else:
data[symbol][date]['SellValue'] = 0
Dùng hàm compute_profit
ở mục 1 chúng ta có thể tính được hiệu suất đầu tư của khối ngoại với từng mã, sau đây là kết quả với một vài mã
Chúng ta sẽ tính toán lợi nhuận đầu tư của khối ngoại cho tất cả các cổ phiếu
profit_lastday = {}
for symbol in list_symbol:
_, all_profit = compute_profit(symbol)
profit_lastday[symbol] = all_profit[-1]
sum([profit_lastday[k] for k in profit_lastday])
Kết quả in ra là -13214.18, Vậy khối ngoại đã mất hơn 13,000 tỷ so với trường hợp giữ nguyên danh mục kể từ ngày 1/8/2021 đến ngày chúng tôi làm thống kê là 1/8/2025, chúng ta hãy cùng xem những cổ phiếu mà tự doanh lãi và lỗ nhiều nhất ở hình bên dưới
Qua các nghiên cứu trên, chúng ta có thể thấy hiệu quả đi lệnh của cả tự doanh lẫn khối ngoại là không tốt. Cả khối ngoại lẫn tự doanh đã mất hàng chục nghìn tỷ so với việc chỉ cần giữ nguyên danh mục kể từ ngày đầu thống kê. Vậy tại sao bạn vẫn nhìn vào và phân tích khối ngoại, tự doanh mua bán?. Tải và thực thi đoạn code trong bài viết tại đây