Khi viết một chiến lược giao dịch định lượng, sử dụng dữ liệu đường K, thường có trường hợp mà dữ liệu đường K chu kỳ không chuẩn được yêu cầu. ví dụ, dữ liệu đường K chu kỳ 12 phút và dữ liệu chu kỳ đường K 4 giờ được yêu cầu. Thông thường các chu kỳ không chuẩn như vậy không trực tiếp có sẵn. Vậy làm thế nào để chúng ta giải quyết những nhu cầu như vậy?
Dữ liệu đường K chu kỳ không chuẩn có thể được thu được bằng cách kết hợp dữ liệu của chu kỳ nhỏ hơn. Hình ảnh này, giá cao nhất trong nhiều chu kỳ được tính là giá cao nhất sau tổng hợp đường K chu kỳ nhiều, và giá thấp nhất được tính là giá thấp nhất sau tổng hợp, và giá mở không thay đổi. Giá mở đầu tiên của dữ liệu nguyên liệu của đường K được tổng hợp. Giá đóng tương ứng với giá đóng của dữ liệu nguyên liệu cuối cùng của đường K. Thời gian sử dụng thời gian của đường giá mở k. Khối lượng giao dịch sử dụng dữ liệu nguyên liệu tổng hợp và tính toán.
Như trong hình:
Hãy lấy tài sản blockchain BTC_USDT làm ví dụ và tổng hợp 1 giờ thành 4 giờ.
Thời gian | cao nhất | Mở | Tối thiểu nhất | Gắn lại |
---|---|---|---|---|
2019.8.12 00:00 | 11447.07 | 11382.57 | 11367.2 | 11406.92 |
2019.8.12 01:00 | 11420 | 11405.65 | 11366.6 | 11373.83 |
2019.8.12 02:00 | 11419.24 | 11374.68 | 11365.51 | 11398.19 |
2019.8.12 03:00 | 11407.88 | 11398.59 | 11369.7 | 11384.71 |
Dữ liệu của bốn chu kỳ 1 giờ được kết hợp thành một dữ liệu chu kỳ 4 giờ duy nhất.
Giá mở là giá mở đầu tiên K dòng tại 00:00 thời gian: 11382.57 Giá đóng là giá đóng k dòng cuối cùng lúc 03:00: 11384.71 Giá cao nhất là tìm giá cao nhất trong số họ: 11447.07 Giá thấp nhất là tìm giá thấp nhất trong số họ: 11365.51
Lưu ý: Thị trường tương lai hàng hóa Trung Quốc đóng cửa lúc 15:00 vào một ngày giao dịch bình thường
Thời gian bắt đầu chu kỳ 4 giờ là thời gian bắt đầu của đường K 1 giờ đầu tiên, tức là 2019.8.12 00:00
Tổng khối lượng của tất cả các dòng k 1 giờ được sử dụng như khối lượng dòng k 4 giờ này.
Một dòng K 4 giờ được tổng hợp:
High: 11447.07
Open: 11382.57
Low: 11365.51
Close: 11384.71
Time: 209.8.12 00:00
Bạn có thể thấy rằng dữ liệu là phù hợp.
Sau khi hiểu được những ý tưởng ban đầu, bạn có thể tự viết mã để thực hiện các yêu cầu.
Mã này chỉ dùng để tham khảo:
function GetNewCycleRecords (sourceRecords, targetCycle) { // K line synthesis function
var ret = []
// First get the source K line data cycle
if (!sourceRecords || sourceRecords.length < 2) {
Return null
}
var sourceLen = sourceRecords.length
var sourceCycle = sourceRecords[sourceLen - 1].Time - sourceRecords[sourceLen - 2].Time
if (targetCycle % sourceCycle != 0) {
Log("targetCycle:", targetCycle)
Log("sourceCycle:", sourceCycle)
throw "targetCycle is not an integral multiple of sourceCycle."
}
if ((1000 * 60 * 60) % targetCycle != 0 && (1000 * 60 * 60 * 24) % targetCycle != 0) {
Log("targetCycle:", targetCycle)
Log("sourceCycle:", sourceCycle)
Log((1000 * 60 * 60) % targetCycle, (1000 * 60 * 60 * 24) % targetCycle)
throw "targetCycle cannot complete the cycle."
}
var multiple = targetCycle / sourceCycle
var isBegin = false
var count = 0
var high = 0
var low = 0
var open = 0
var close = 0
var time = 0
var vol = 0
for (var i = 0 ; i < sourceLen ; i++) {
// Get the time zone offset value
var d = new Date()
var n = d.getTimezoneOffset()
if ((1000 * 60 * 60 * 24) - sourceRecords[i].Time % (1000 * 60 * 60 * 24) + (n * 1000 * 60)) % targetCycle == 0) {
isBegin = true
}
if (isBegin) {
if (count == 0) {
High = sourceRecords[i].High
Low = sourceRecords[i].Low
Open = sourceRecords[i].Open
Close = sourceRecords[i].Close
Time = sourceRecords[i].Time
Vol = sourceRecords[i].Volume
count++
} else if (count < multiple) {
High = Math.max(high, sourceRecords[i].High)
Low = Math.min(low, sourceRecords[i].Low)
Close = sourceRecords[i].Close
Vol += sourceRecords[i].Volume
count++
}
if (count == multiple || i == sourceLen - 1) {
Ret.push({
High : high,
Low : low,
Open : open,
Close : close,
Time : time,
Volume : vol,
})
count = 0
}
}
}
Return ret
}
// test
function main () {
while (true) {
var r = exchange.GetRecords() // Raw data, as the basic K-line data of the synthesize K line. for example, to synthesize a 4-hour K-line, you can use the 1-hour K-line as the raw data.
var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4) // Pass the original K-line data r through the GetNewCycleRecords function, and the target cycles, 1000 * 60 * 60 * 4, ie the target synthesis cycle is 4 hours K-line data .
$.PlotRecords(r2, "r2") // The strategy class library bar can be selected by check the line class library, and calling the $.PlotRecords line drawing class library to export the function drawing.
Sleep(1000) // Each cycle is separated by 1000 milliseconds, preventing access to the K-line interface too much, resulting in transaction restrictions.
}
}
Trong thực tế, để tổng hợp đường K, bạn cần hai thứ. thứ nhất là dữ liệu nguyên liệu thô, nghĩa là dữ liệu đường K của một chu kỳ nhỏ hơn. trong ví dụ này, nó làvar r = exchange.GetRecords()
để có được dữ liệu đường K chu kỳ nhỏ hơn.
Thứ hai là để tìm ra kích thước của chu kỳ tổng hợp, chúng tôi sử dụng thuật toán chức năng GetNewCycleRecords để làm điều này, sau đó bạn cuối cùng có thể trả về dữ liệu của một cấu trúc mảng K-line tổng hợp.
Xin lưu ý:
Chu kỳ mục tiêu không thể nhỏ hơn chu kỳ của đường K mà bạn đã vượt qua trong chức năng GetNewCycleRecords như một nguyên liệu thô cho dữ liệu. Bởi vì bạn không thể tổng hợp dữ liệu chu kỳ nhỏ hơn bằng một chu kỳ lớn hơn. chỉ ngược lại.
Chu kỳ mục tiêu phải được đặt thành
ví dụ:
Dòng K của chu kỳ 12 phút bắt đầu từ 0:0 mỗi giờ, chu kỳ đầu tiên là 00:00:00 ~ 00:12:00, và chu kỳ thứ hai là 00:12: 00 ~ 00: 24:00, chu kỳ thứ ba là 00:24: 00 ~ 00:36:00, chu kỳ thứ tư là 00:36:00 ~ 00:48:00, chu kỳ thứ năm là 00:48 :00 ~ 01:00:00, chính xác là một giờ hoàn thành.
Nếu nó là một chu kỳ 13 phút, nó sẽ là một chu kỳ không đóng. Dữ liệu được tính bằng chu kỳ như vậy không phải là duy nhất vì dữ liệu tổng hợp khác nhau tùy thuộc vào điểm khởi đầu của dữ liệu tổng hợp.
Chạy nó trên thị trường thực tế:
Biểu đồ trao đổi tương phản
Tôi muốn tính trung bình động của giá cao nhất cho tất cả các đường K. Tôi nên làm gì?
Thông thường, chúng tôi tính toán các đường trung bình động bằng cách sử dụng giá trung bình của giá đóng cửa, nhưng đôi khi có nhu cầu sử dụng giá cao nhất, giá thấp nhất, giá mở cửa và vân vân.
Đối với các yêu cầu bổ sung này, dữ liệu đường K được trả về bởi hàm exchange.GetRecords (()) không thể được truyền trực tiếp đến hàm tính toán chỉ số.
Ví dụ:
Cáctalib.MA
Chức năng tính toán chỉ số trung bình động có hai tham số, một là dữ liệu cần được truyền vào và thứ hai là tham số chu kỳ chỉ số.
ví dụ, chúng ta cần tính toán các chỉ số như được hiển thị dưới đây.
Chu kỳ đường K là 4 giờ.
Trên biểu đồ báo giá thị trường chứng khoán, một đường trung bình đã được thiết lập với tham số chu kỳ là 9.
Nguồn dữ liệu được tính toán sử dụng giá cao nhất cho mỗi Bar.
Đó là, đường trung bình động này bao gồm trung bình của giá trung bình cao nhất của chín 4-giờ chu kỳ K-line Bar.
Chúng ta hãy tự xây dựng một dữ liệu để xem liệu nó có giống nhau với dữ liệu của sàn giao dịch không.
var highs = []
for (var i = 0 ; i < r2.length ; i++) {
highs.push(r2[i].High)
}
Vì chúng ta cần tính toán giá cao nhất của mỗi Bar để có được giá trị của chỉ số trung bình động, chúng ta cần xây dựng một mảng trong đó mỗi yếu tố dữ liệu có giá cao nhất cho mỗi Bar.
Bạn có thể thấy rằnghighs
biến là ban đầu một mảng trống, sau đó chúng ta đi qua biến dữ liệu r2 k-line (không nhớ r2? Hãy nhìn vào mã trong hàm chính tổng hợp 4-hour K-line ở trên).
Đọc giá cao nhất của mỗi Bar của r2 (tức là r2[i].High, i dao động từ 0 đến r2.length - 1), sau đó nhấn vàohighs
Bằng cách này chúng ta chỉ cần xây dựng một cấu trúc dữ liệu tương ứng một-một với K-đường dữ liệu thanh.
Vào lúc này,highs
có thể vượt quatalib.MA
chức năng để tính trung bình động.
Ví dụ đầy đủ:
function main () {
while (true) {
var r = exchange.GetRecords()
var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4)
if (!r2) {
Continue
}
$.PlotRecords(r2, "r2") // Draw the K line
var highs = []
for (var i = 0 ; i < r2.length ; i++) {
Highs.push(r2[i].High)
}
var ma = talib.MA(highs, 9) // use the moving average function "talib.MA" to calculate the moving average indicator
$.PlotLine("high_MA9", ma[ma.length - 2], r2[r2.length - 2].Time) // Use the line drawing library to draw the moving average indicator on the chart
Sleep(1000)
}
}
Kiểm tra hậu quả:
Bạn có thể thấy rằng giá trị chỉ số trung bình của vị trí điểm chuột trong hình là 11466.9289
Mã ở trên có thể được sao chép vào chiến lược để chạy thử nghiệm, hãy nhớ kiểm tra thư viện đường vẽ và lưu nó!
Nền tảng FMZ Quant đã có một giao diện đóng gói, cụ thể là
exchange.GetRecords
chức năng, để có được dữ liệu đường K.
Sau đây tập trung vào việc truy cập trực tiếp vào giao diện dữ liệu K-line của trao đổi để lấy dữ liệu, bởi vì đôi khi bạn cần phải chỉ định các tham số để có được nhiều hơn K dòng, góiGetRecords
giao diện thường trả về 100 k dòng. nếu bạn gặp một chiến lược ban đầu đòi hỏi hơn 100 K-dòng, bạn cần phải chờ quá trình thu thập.
Để làm cho chiến lược hoạt động càng sớm càng tốt, bạn có thể đóng gói một hàm, truy cập trực tiếp vào giao diện đường K của sàn giao dịch, và chỉ định các tham số để có được nhiều dữ liệu đường K hơn.
Sử dụng cặp giao dịch BTC_USDT trên sàn giao dịch Huobi làm ví dụ, chúng tôi thực hiện yêu cầu sau:
Tìm tài liệu API của trao đổi và xem mô tả giao diện K-line:
https://huobiapi.github.io/docs/spot/v1/en/#get-klines-candles
Các thông số:
Tên | Loại | Có cần thiết? | Mô tả | Giá trị |
---|---|---|---|---|
biểu tượng | chuỗi | đúng | Cặp giao dịch | Btcusdt, ethbtc... |
thời gian | chuỗi | đúng | Trả về độ chi tiết thời gian của dữ liệu, đó là khoảng thời gian của mỗi dòng k | 1 phút, 5 phút, 15 phút, 30 phút, 60 phút, 1 ngày, 1 tháng, 1 tuần, 1 năm |
kích thước | số nguyên | sai | Trả về số K dòng dữ liệu | [1, 2000] |
Mã thử nghiệm:
function GetRecords_Huobi (period, size, symbol) {
var url = "https://api.huobi.pro/market/history/kline?" + "period=" + period + "&size=" + size + "&symbol=" + symbol
var ret = HttpQuery(url)
try {
var jsonData = JSON.parse(ret)
var records = []
for (var i = jsonData.data.length - 1; i >= 0 ; i--) {
records.push({
Time : jsonData.data[i].id * 1000,
High : jsonData.data[i].high,
Open : jsonData.data[i].open,
Low : jsonData.data[i].low,
Close : jsonData.data[i].close,
Volume : jsonData.data[i].vol,
})
}
return records
} catch (e) {
Log(e)
}
}
function main() {
var records = GetRecords_Huobi("1day", "300", "btcusdt")
Log(records.length)
$.PlotRecords(records, "K")
}
Bạn có thể thấy trên nhật ký, inrecords.length
là 300, nghĩa là số lượngrecords
Dây dữ liệu đường K là 300.