Vài tuần trước, tôi quyết định xây dựng một robot Polymarket của riêng mình. Phiên bản hoàn chỉnh đã tốn của tôi vài tuần.
Tôi sẵn sàng bỏ ra công sức này vì trên Polymarket thực sự tồn tại những lỗ hổng hiệu suất. Mặc dù đã có một số robot trên thị trường khai thác những điểm không hiệu quả này để kiếm lời, nhưng vẫn chưa đủ. Cơ hội trên thị trường này vẫn nhiều hơn rất nhiều so với số lượng robot.
Logic xây dựng robot
Logic của robot này dựa trên một chiến lược mà tôi đã thực hiện thủ công trước đây. Để nâng cao hiệu quả, tôi đã tự động hóa nó. Robot này chạy trên thị trường "BTC 15 phút TĂNG / GIẢM (BTC 15-minute UP/DOWN)".
Robot chạy một chương trình giám sát thời gian thực, có thể tự động chuyển đổi sang vòng BTC 15 phút hiện tại, truyền phát giá mua/giá bán tốt nhất (best bid/ask) qua WebSocket, hiển thị giao diện người dùng (UI) đầu cuối cố định và cho phép kiểm soát toàn diện thông qua các lệnh văn bản.
Ở chế độ thủ công, bạn có thể đặt lệnh trực tiếp.
buy up
buyshares up
Chế độ tự động chạy một vòng lặp hai giai đoạn (two-leg) lặp lại.
Bước đầu tiên, nó chỉ quan sát biến động giá trong windowMin phút đầu tiên sau khi mỗi vòng bắt đầu. Nếu bất kỳ bên nào giảm đủ nhanh (giảm ít nhất movePct trong khoảng 3 giây), nó sẽ kích hoạt "Giai đoạn 1 (Leg 1)", mua vào bên vừa giảm mạnh.
Sau khi hoàn thành Leg 1, robot sẽ không bao giờ mua lại cùng một bên. Nó sẽ chờ "Giai đoạn 2 (Leg 2, tức là phòng ngừa rủi ro - hedge)" và chỉ kích hoạt khi điều kiện sau được thỏa mãn: leg1EntryPrice + oppositeAsk <= sumTarget.
Khi điều kiện này được đáp ứng, nó sẽ mua vào bên ngược lại. Sau khi Leg 2 hoàn tất, vòng lặp kết thúc và robot quay trở lại trạng thái quan sát, chờ đợi tín hiệu giảm mạnh tiếp theo với các thiết lập tham số tương tự.
Nếu vòng đấu thay đổi trong quá trình vòng lặp, robot sẽ từ bỏ vòng lặp đang mở và bắt đầu lại với các thiết lập giống nhau ở vòng tiếp theo.
Các tham số cho chế độ tự động được thiết lập như sau: auto on
· shares: Kích thước vị thế được sử dụng cho cả hai giao dịch (legs).
· sum: Ngưỡng cho phép phòng ngừa rủi ro (hedge).
· move (movePct): Ngưỡng giảm mạnh (ví dụ: 0.15 = 15%).
· windowMin: Khoảng thời gian tính từ đầu mỗi vòng, cho phép thực hiện Leg 1.
Kiểm tra ngược (Backtest)
Logic của robot rất đơn giản: Chờ đợi đợt bán tháo mạnh, mua vào bên vừa mới giảm xong, sau đó chờ giá ổn định và phòng ngừa rủi ro bằng cách mua vào bên ngược lại, đồng thời đảm bảo: priceUP + priceDOWN < 1.
Nhưng logic này cần được kiểm tra. Về lâu dài, nó có thực sự hiệu quả? Quan trọng hơn, robot có rất nhiều tham số (số cổ phiết, tổng sum, phần trăm di chuyển, số phút cửa sổ, v.v.). Bộ tham số nào là tối ưu và có thể tối đa hóa lợi nhuận?
Suy nghĩ đầu tiên của tôi là cho robot chạy thực tế trong một tuần và quan sát kết quả. Vấn đề là cách này quá tốn thời gian và chỉ có thể kiểm tra một bộ tham số, trong khi tôi cần kiểm tra rất nhiều bộ.
Suy nghĩ thứ hai của tôi là sử dụng dữ liệu lịch sử trực tuyến từ Polymarket CLOB API để kiểm tra ngược. Thật không may, đối với thị trường BTC 15 phút Tăng/Giảm, điểm cuối dữ liệu lịch sử liên tục trả về tập dữ liệu trống. Không có dữ liệu giá lịch sử (ticks), việc kiểm tra ngược không thể phát hiện "đợt giảm mạnh trong khoảng 3 giây", do đó không thể kích hoạt Leg 1, và bất kể tham số nào, cũng sẽ tạo ra 0 vòng lặp và tỷ suất lợi nhuận (ROI) 0%.
Sau khi điều tra thêm, tôi phát hiện ra rằng những người dùng khác cũng gặp phải vấn đề tương tự khi cố gắng lấy dữ liệu lịch sử cho một số thị trường nhất định. Tôi đã thử nghiệm các thị trường khác thực sự trả về dữ liệu lịch sử và kết luận rằng: đối với thị trường cụ thể này, dữ liệu lịch sử đơn giản là không được lưu giữ.
Do hạn chế này, phương pháp kiểm tra ngược chiến lược này một cách đáng tin cậy duy nhất là tạo ra tập dữ liệu lịch sử của riêng tôi bằng cách ghi lại giá bán tốt nhất (best-ask) thời gian thực trong khi robot đang chạy.
Trình ghi (logger) sẽ ghi ảnh chụp nhanh (snapshot) vào đĩa, bao gồm những nội dung sau:
· Dấu thời gian (Timestamp)
· Định danh vòng (Round slug)
· Số giây còn lại
· ID token UP/DOWN
· Giá bán tốt nhất UP/DOWN (UP/DOWN best-ask)
Sau đó, "kiểm tra ngược đã ghi (recorded backtest)" sẽ phát lại các ảnh chụp nhanh này và áp dụng cùng một logic tự động một cách xác định. Điều này đảm bảo có được dữ liệu tần số cao cần thiết để phát hiện các đợt giảm mạnh và điều kiện phòng ngừa rủi ro.
Tôi đã thu thập tổng cộng 6 GB dữ liệu trong 4 ngày. Tôi có thể ghi lại nhiều hơn, nhưng tôi nghĩ rằng thế là đủ để kiểm tra các bộ tham số khác nhau.
Tôi bắt đầu thử nghiệm bộ tham số này:
· Số dư ban đầu: $1,000
· 20 cổ phiết mỗi giao dịch
· sumTarget = 0.95
· Ngưỡng giảm mạnh = 15%
· windowMin = 2 phút
Tôi cũng áp dụng mức phí cố định 0.5% và chênh lệch giá (spread) 2% để duy trì trong kịch bản thận trọng.
Kiểm tra ngược cho thấy ROI là 86%, $1,000 đã trở thành $1,869 chỉ trong vài ngày.
Sau đó, tôi thử nghiệm một bộ tham số mạnh tay hơn:
· Số dư ban đầu: $1,000
· 20 cổ phiết mỗi giao dịch
· sumTarget = 0.6
· Ngưỡng giảm mạnh = 1%
· windowMin = 15 phút
Kết quả: ROI -50% sau 2 ngày.
Điều này cho thấy rõ ràng rằng việc lựa chọn tham số là yếu tố quan trọng nhất. Nó có thể giúp bạn kiếm được nhiều tiền, nhưng cũng có thể dẫn đến tổn thất lớn.
Hạn chế của kiểm tra ngược
Ngay cả khi đã bao gồm phí và chênh lệch giá, kiểm tra ngược vẫn có những hạn chế của nó.
· Đầu tiên, nó chỉ sử dụng dữ liệu trong vài ngày, điều này có thể không đủ để có cái nhìn toàn diện về thị trường.
· Nó phụ thuộc vào các ảnh chụp nhanh giá bán tốt nhất đã ghi; trong thực tế, lệnh có thể được khớp một phần, hoặc khớp ở các mức giá khác nhau. Hơn nữa, độ sâu sổ lệnh và khối lượng giao dịch khả dụng không được mô hình hóa.
· Không nắm bắt được các biến động vi mô dưới mức giây (dữ liệu được lấy mẫu mỗi giây một lần). Kiểm tra ngược mặc dù có dấu thời gian 1 giây, nhưng nhiều điều có thể xảy ra giữa các giây.
· Trong kiểm tra ngược, trượt giá (slippage) là không đổi, không mô phỏng độ trễ biến đổi (ví dụ: 200–1500 mili giây) hoặc các đỉnh mạng.
· Mỗi giao dịch (leg) được coi là được thực thi "ngay lập tức" (không có lệnh xếp hàng, không có lệnh chờ).
· Phí được tính đồng nhất, trong khi trong thực tế phí có thể phụ thuộc vào: thị trường / token, người đặt lệnh (maker) so với người nhận lệnh (taker), cấp độ phí hoặc điều kiện.
Để bi quan một cách thận trọng, tôi áp dụng một quy tắc: Nếu Leg 2 không được thực thi trước khi thị trường đóng, Leg 1 sẽ được coi là thua lỗ toàn bộ (total loss).
Đây là một giả định cố ý thận trọng, nhưng không phải lúc nào cũng phù hợp với thực tế:
· Đôi khi Leg 1 có thể được đóng sớm,
· Đôi khi nó cuối cùng ở trạng thái trong giá (ITM - In The Money) và thắng,
· Đôi khi tổn thất có thể là một phần chứ không phải toàn bộ.
Mặc dù tổn thất có thể được ước tính quá mức, điều này cung cấp một kịch bản "trường hợp xấu nhất" thực tế.
Quan trọng nhất, kiểm tra ngược không thể mô phỏng tác động của các lệnh lớn của bạn lên sổ lệnh hoặc việc thu hút các nhà giao dịch khác săn lùng bạn. Trong thực tế, lệnh của bạn có thể:
· Làm xáo trộn sổ lệnh,
· Thu hút hoặc xua đuổi các nhà giao dịch khác,
· Dẫn đến trượt giá phi tuyến tính.
Kiểm tra ngược giả định rằng bạn là một người chấp nhận thanh khoản thuần túy (price taker), không có bất kỳ ảnh hưởng nào.
Cuối cùng, nó không mô phỏng giới hạn tần suất (rate limits), lỗi API, lệnh bị từ chối, tạm dừng, quá thời gian, kết nối lại, hoặc robot bận mà bỏ lỡ tín hiệu.
Kiểm tra ngược cực kỳ có giá trị để xác định phạm vi tham số tốt, nhưng nó không phải là đảm bảo 100%, vì một số hiệu ứng thế giới thực không thể được mô hình hóa.
Cơ sở hạ tầng
Tôi dự định chạy robot này trên Raspberry Pi để tránh tiêu hao tài nguyên máy chủ chính của mình và duy trì hoạt động 24/7.
Nhưng điều này vẫn có không gian cải thiện đáng kể:
· Sử dụng Rust thay cho JavaScript sẽ mang lại hiệu suất và thời gian xử lý vượt trội hơn nhiều.
· Chạy một nút RPC Polygon chuyên dụng sẽ further giảm độ trễ.
· Triển khai trên một VPS gần máy chủ Polymarket cũng sẽ giảm độ trễ đáng kể.
Chắc chắn còn có những phương pháp tối ưu hóa khác mà tôi chưa phát hiện ra. Hiện tại, tôi đang học Rust vì nó đang trở thành ngôn ngữ không thể thiếu trong phát triển Web3.














