Type/to search
8
Follow
1364
Followers
Ứng dụng của hàm __Thread trong thiết kế chiến lược JavaScript
Discussions
Created 2023-07-04 16:35:42  Updated 2024-11-11 22:41:32
 3
 1330

img

Ứng dụng của hàm __Thread trong thiết kế chiến lược JavaScript

Trong thiết kế chiến lược FMZ ban đầu, nếu các hoạt động đồng thời không đồng bộ được yêu cầu, chỉexchange.Go()Hàm được sử dụng để triển khai tính đồng thời của giao diện đóng gói FMZ và một số hoạt động tùy chỉnh (hàm) không thể được thực thi đồng thời. Mặc dù thiết kế này cải thiện đáng kể hiệu quả thực hiện chương trình chính sách, nhưng nó vẫn còn rất xa lạ với những sinh viên có kinh nghiệm thiết kế đồng thời bằng ngôn ngữ lập trình gốc.

Ngay cả một số sinh viên mới làm quen với giao dịch định lượng bằng FMZ cũng không hiểuexchange.Go()Sử dụng các hàm, sử dụngexchange.Go()Có vẻ như các câu lệnh vẫn được thực thi từng câu một trong mã được thực thi tuần tự. Trong bài viết này, chúng ta hãy cùng khám phá các tính năng luồng đồng thời mới của nền tảng FMZ:__Thread()Việc sử dụng một loạt các chức năng và chiến lược chương trình thiết kế không đồng bộ.

1. Thiết kế đồng thời đơn giản

Nếu chúng ta muốn chạy một luồng con đồng thời để thực thi một hàm tùy chỉnh mà chúng ta đã viết trong khi luồng chính chiến lược đang chạy, chúng ta có thể sử dụng thiết kế tương tự như mã sau. Tùy chỉnh một chức năng trong mã chiến lượcGetTickerAsync(), hãy viết chức năng cụ thể của hàm này. Hàm này thực hiện một vòng lặp vô hạn.whileGiao diện API FMZ được gọi liên tục trong một vòng lặp:GetTicker()Để có được dữ liệu thị trường.

Sau đó sử dụng__threadSetData(0, "ticker", t)Câu này ghi dữ liệu vào luồng chính. Tên dữ liệu làticker, giá trị dữ liệu làtNgay lập tứcGetTicker()Giá trị trả về của .

javascript
__threadSetData(0, "ticker", t)

Sau khi thiết kế hàm tùy chỉnh để thực thi đồng thời các luồng, chúng ta có thể viếtmain()Mã trong hàm làmain()Khi bắt đầu hàm, chúng ta sử dụng:

javascript
__Thread(GetTickerAsync, 0) // GetTickerAsync为需要并发执行的自定义函数,0为这个传入GetTickerAsync函数的参数

Tạo một luồng đồng thời, bắt đầu thực thiGetTickerAsync()chức năng. sau đómain()Chức năng bắt đầu thực hiệnwhileVòng lặp, nhận trong vòng lặpGetTickerAsync()Hàm này cập nhật dữ liệu và sau đó in ra:

javascript
var t = __threadGetData(0, "ticker") Log(t)

Ví dụ mã đầy đủ:

javascript
function GetTickerAsync(index) { while (true) { var t = exchanges[index].GetTicker() __threadSetData(0, "ticker", t) Sleep(500) } } function main() { __Thread(GetTickerAsync, 0) while(true) { var t = __threadGetData(0, "ticker") Log(t) Sleep(1000) } }

Kiểm tra hoạt động của đĩa thực tế:

img

Đây là thiết kế ứng dụng đơn giản nhất. Tiếp theo, chúng ta hãy xem một số thiết kế nhu cầu khác.

2. Thiết kế lệnh đồng thời

Có thể thiết kế một hàm để tạo ra 10 luồng cùng lúc và mỗi luồng thực thi một hàm thao tác lệnh. hiện hữumain()Thiết kế một chức năngwhileVòng lặp, hướng dẫn tương tác chiến lược phát hiện. Nhận hướng dẫn tương tác:placeMultipleOrdersChỉ cần gọi hàm thứ tự đồng thời nàytestPlaceMultipleOrders()

javascript
if (cmd == "placeMultipleOrders") { // ... }

Thêm thiết kế tương tác chiến lược vào trang chỉnh sửa chiến lược và đặt nút bằng lệnh: placeMultipleOrders

img

Ví dụ mã đầy đủ:

javascript
function placeOrder(exIndex, type, price, amount) { var id = null if (type == "Buy") { id = exchanges[exIndex].Buy(price, amount) } else if (type == "Sell") { id = exchanges[exIndex].Sell(price, amount) } else { throw "type error! type:" + type } } function testPlaceMultipleOrders(index, beginPrice, endPrice, step, type, amount) { Log("beginPrice:", beginPrice, ", endPrice:", endPrice, ", step:", step, ", type:", type, ", amount:", amount) var tids = [] for (var p = beginPrice; p <= endPrice; p += step) { var tid = __Thread(placeOrder, index, type, p, amount) tids.push(tid) Sleep(10) } Sleep(1000) for (var i = 0; i < tids.length; i++) { __threadTerminate(tids[i]) } } function main() { while(true) { LogStatus(_D()) var cmd = GetCommand() if (cmd) { if (cmd == "placeMultipleOrders") { var t = _C(exchange.GetTicker) var beginPrice = t.Last * 0.8 var endPrice = t.Last * 0.9 var step = t.Last * 0.01 testPlaceMultipleOrders(0, beginPrice, endPrice, step, "Buy", 0.01) var orders = exchange.GetOrders() for (var i = 0; i < orders.length; i++) { Log(orders[i]) } } } Sleep(1000) } }
  • Bài kiểm tra sử dụng phương pháp lệnh chờ, tăng từ 80% đến 90% giá hiện tại, sử dụng thử nghiệm môi trường đĩa mô phỏng và nhấp vào nút tương tác để kích hoạt lệnh kiểm tra:

    img

  • Sau khi nhấp vào nút "placeMultipleOrders", thông báo nhắc nhở sẽ là:

    img

  • Nhật ký chiến lược hiển thị các hoạt động đặt hàng đồng thời:

    img

3. Tạo kết nối WebSocket trong hàm thực thi luồng đồng thời

Yêu cầu này được đưa ra bởi một người dùng FMZ muốn có một ví dụ đơn giản để chứng minh cách sử dụng nó trong các luồng đồng thời.WebSocketKết nối và thiết kế cách truyền dữ liệu đến luồng chínhmain()chức năng.

Trên thực tế, nó rất đơn giản và tương tự như việc tạo các luồng đồng thời trong ví dụ trước. Chỉ sử dụng giao tiếp giữa các luồng__threadPeekMessage()Chức năng và__threadPostMessage()chức năng. Lấy ví dụ về lệnh gọi giao diện API WebSocket của Binance Exchange, chúng ta cũng cần chú ý đến thao tác đóng kết nối WebSocket trong thiết kế. Ví dụ sau đây cũng cho thấy cách thông báo cho một luồng đồng thời dừng nó.

Ví dụ mã đầy đủ:

javascript
var tid = null function createWS() { // wss://stream.binance.com:9443/ws/<streamName> , <symbol>@ticker var stream = "wss://stream.binance.com:9443/ws/btcusdt@ticker" var ws = Dial(stream) Log("创建WS连接:", stream) while (true) { var data = ws.read() if (data) { __threadPostMessage(0, data) } Log("接收到WS链接推送的数据,data:", data) // __threadPeekMessage 超时参数设置-1,不阻塞 var msg = __threadPeekMessage(-1) if (msg) { if (msg == "stop") { Log("并发线程Id:", __threadId(), "接收到stop指令") break } } } Log("并发线程执行完毕,关闭ws连接") ws.close() } function main() { tid = __Thread(createWS) Log("创建并发线程,线程Id:", tid) while(true) { // __threadPeekMessage 的超时参数设置为0,阻塞等待数据 var data = __threadPeekMessage(0) Log("接收到并发线程", ", Id:", tid, ", 发送的数据,data:", data, "#FF0000") var tbl = { type : "table", title : "<symbol>@ticker频道推送消息", cols : ["事件类型", "事件时间", "交易对", "24小时价格变化", "24小时价格变化百分比", "平均价格", "最新成交价格", "24小时内成交量", "24小时内成交额"], rows : [] } try { data = JSON.parse(data) tbl.rows.push([data.e, _D(data.E), data.s, data.p, data.P, data.w, data.c, data.v, data.q]) } catch (e) { Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message) } LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`") } } function onexit() { Log("扫尾函数,向Id为", tid, "的并发线程发送stop指令") __threadPostMessage(tid, "stop") Log("等待Id为", tid, "的并发线程停止") __threadJoin(tid) Log("扫尾函数执行完毕") }

Kiểm tra hoạt động của đĩa thực tế:

img

Bạn có thể thấymain()Chức năng này liên tục nhận dữ liệu thị trường từ kết nối WebSocket được tạo bởi luồng đồng thời.

Khi chiến lược dừng lại, chức năng quét sẽ bắt đầu hoạt động:

img

Comment
All comments (3)

    最后一个实例,如果ws线程很多,并且订阅了多个话题,那么线程间通信的话,使用get/set的方式还是peek/post的方式哪种性能更好呢

    3 years ago

    两种方式差别不大的,都可以。

    3 years ago

    线程间共享变量的底层实现是不支持引用变量的,每次更新都得重新set,这效率很低

    3 years ago
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)