
Membuat bagan dan menggambar grafik sering digunakan saat menulis dan merancang strategi. Untuk bagan khusus tunggal, kita dapat menggunakanPerpustakaan gambar garis(Siswa yang belum familiar dengan konsep template library pada FMZ dapat mengecek dokumentasi API FMZ), yang sangat memudahkan untuk operasi menggambar. Akan tetapi, pustaka templat ini tidak dapat memenuhi kebutuhan skenario yang memerlukan beberapa bagan. Lalu kita mempelajari ide desain dari pustaka gambar garis ini, dan mendesain versi multi-bagan dari pustaka gambar garis berdasarkan ini.
Mengacu pada desain fungsi ekspor “Perpustakaan Gambar Garis”, kami juga merancang fungsi ekspor serupa untuk pustaka gambar garis multi-bagan.
$.PlotMultRecords
Digunakan untuk menggambar grafik garis K, desain parameter: cfgName, seriesName, records, extension.
cfgName: Nama objek konfigurasi sebagai bagan terpisah.
seriesName: Nama seri data K-line yang saat ini akan diplot.
catatan: data K-line yang masuk.
ekstensi: Informasi konfigurasi ukuran grafik, misalnya, diteruskan ke:{layout: 'single', col: 6, height: '600px'}, yaitu, biarkan bagan dengan nama objek konfigurasi cfgName ditampilkan secara terpisah, dengan lebar 6 dan tinggi 600px.
$.PlotMultLine Digunakan untuk menggambar garis, desain parameter: cfgName, seriesName, dot, ts, extension cfgName: Nama objek konfigurasi sebagai bagan terpisah. seriesName: Nama seri data yang akan digambar. titik: Nilai koordinat vertikal titik pada garis yang akan digambar. ts: Cap waktu, yaitu nilai pada sumbu waktu x. ekstensi: Informasi konfigurasi untuk ukuran grafik.
$.PlotMultHLine
Digunakan untuk menggambar garis horizontal, desain parameter: cfgName, nilai, label, warna, gaya
cfgName : Nama objek konfigurasi bagan.
nilai: Nilai koordinat vertikal garis horizontal.
label: Teks yang ditampilkan pada garis horizontal.
warna : Warna garis.
style : Gaya garis, misalnya:Solid ShortDash ShortDot ShortDashDot ShortDashDotDot Dot Dash LongDash DashDot LongDashDot LongDashDotDot。
$.PlotMultTitle Digunakan untuk mengubah judul dan subjudul bagan. Desain parameter: cfgName, judul, chartTitle cfgName : Nama objek konfigurasi bagan. judul: Subjudul. chartTitle : Judul bagan.
$.PlotMultFlag Gambar ikon bendera kecil, desain parameter: cfgName, seriesName, ts, teks, judul, bentuk, warna, onSeriesName cfgName : Nama objek konfigurasi bagan. seriesName : nama seri data. ts : cap waktu teks: Teks dalam ikon kecil. judul: Judul ikon kecil. bentuk: Bentuk ikon kecil. warna: warna ikon kecil. onSeriesName: Berdasarkan seri data mana yang ditampilkan, nilainya adalah id seri data.
$.GetArrCfg Mengembalikan array objek konfigurasi bagan.
Agar lebih mudah dipahami, saya menulis komentar langsung pada fungsi pengujian untuk menjelaskan apa yang dilakukan setiap pemanggilan fungsi.
// test
function main() {
LogReset(10)
var i = 0
var prePrintTs = 0
while (true) {
var r = exchange.GetRecords() // 获取K线数据
var t = exchange.GetTicker() // 获取实时的tick数据
$.PlotMultRecords("chart1", "kline1", r, {layout: 'single', col: 6, height: '600px'}) // 创建一个名为chart1的K线图表,独立显示,宽度是6,高度是600px,K线数据系列名称为kline1,使用上面获取的r作为数据源画图
$.PlotMultRecords("chart2", "kline2", r, {layout: 'single', col: 6, height: '600px'}) // 创建第二个K线图表,名为chart2
$.PlotMultLine("chart2", "line1", t.Last, r[r.length - 1].Time) // 在K线图表即chart2上增加一条线,数据系列名称为line1,使用当前的tick数据的最新价Last作为线上的点的Y值。K线数据的最后一个BAR的时间戳作为X值
$.PlotMultLine("chart3", "line2", t.Last) // 创建一个只画线的图表,图表名称chart3,数据系列名称line2,使用实时tick数据的Last最新价格在当前时间(X值)画一个点(t.Last为Y值),注意图表不是独立显示
$.PlotMultLine("chart6", "line6", t.Time) // 创建一个只画线的图表chart6,注意图表不是独立显示,会和chart3在一起分页显示
$.PlotMultLine("chart4", "line3", t.Sell, new Date().getTime(), {layout: 'single', col: 4, height: '300px'}) // 创建一个只画线的图表chart4,独立显示,宽度4,高度300px
$.PlotMultLine("chart5", "line4", t.Volume, new Date().getTime(), {layout: 'single', col: 8, height: '300px'}) // 创建一个只画线的图表chart5,独立显示,宽度8,高度300px
$.PlotMultHLine("chart1", r[r.length - 1].Close, "HLine1", "blue", "ShortDot") // 给图表chart1增加水平横线
$.PlotMultHLine("chart4", t.Sell, "HLine2", "green") // 给图表chart4增加水平横线
$.PlotMultTitle("chart3", "change : chart3->test1", "test1") // 修改chart3的标题
var ts = new Date().getTime()
if (ts - prePrintTs > 1000 * 20) {
prePrintTs = ts
// 触发时,给chart3图表上画小图标
$.PlotMultFlag("chart3", "flag1", new Date().getTime(), "flag test", "flag1")
}
if (i == 10) {
Log("i == 10")
// 触发时,给chart4,chart1上画小图标
$.PlotMultFlag("chart4", "flag2", new Date().getTime(), "flag test", "flag2")
$.PlotMultFlag("chart1", "flag3", new Date().getTime(), "flag test", "flag3", "squarepin", "green", "kline1")
} else if (i == 20) {
Log("i == 20")
// 触发时,给chart1上添加一条线,但是只画了这条线的一个点,X坐标时间戳,Y坐标为t.Last值
$.PlotMultLine("chart1", "line5", t.Last, r[r.length - 1].Time)
} else if (i == 30) {
Log("i == 30")
// 触发时,给chart2上画小图标
$.PlotMultFlag("chart2", "flag4", new Date().getTime(), "flag test", "flag4", "circlepin", "black", "kline2")
}
Sleep(1000 * 5)
i++
}
}


Anda dapat melihat bahwa hanya dengan satu baris pemanggilan fungsi, Anda dapat dengan mudah menggambar bagan, dan Anda dapat menampilkan beberapa bagan sekaligus.
Konfigurasi parameter:

Implementasi kode sumber pustaka kelas:
var registerInfo = {}
var chart = null
var arrCfg = []
function updateSeriesIdx() {
var index = 0
var map = {}
_.each(arrCfg, function(cfg) {
_.each(cfg.series, function(series) {
var key = cfg.name + "|" + series.name
map[key] = index
index++
})
})
for (var cfgName in registerInfo) {
_.each(arrCfg, function(cfg, cfgIdx) {
if (cfg.name == cfgName) {
registerInfo[cfgName].cfgIdx = cfgIdx
}
})
for (var i in registerInfo[cfgName].seriesIdxs) {
var seriesName = registerInfo[cfgName].seriesIdxs[i].seriesName
var key = cfgName + "|" + seriesName
if (typeof(map[key]) != "undefined") {
registerInfo[cfgName].seriesIdxs[i].index = map[key]
}
if (registerInfo[cfgName].seriesIdxs[i].type == "candlestick") {
registerInfo[cfgName].seriesIdxs[i].preBarTime = 0
} else if (registerInfo[cfgName].seriesIdxs[i].type == "line") {
registerInfo[cfgName].seriesIdxs[i].preDotTime = 0
} else if (registerInfo[cfgName].seriesIdxs[i].type == "flag") {
registerInfo[cfgName].seriesIdxs[i].preFlagTime = 0
}
}
}
if (!chart) {
chart = Chart(arrCfg)
}
chart.update(arrCfg)
chart.reset()
_G("registerInfo", registerInfo)
_G("arrCfg", arrCfg)
for (var cfgName in registerInfo) {
for (var i in registerInfo[cfgName].seriesIdxs) {
var buffer = registerInfo[cfgName].seriesIdxs[i].buffer
var index = registerInfo[cfgName].seriesIdxs[i].index
if (buffer && buffer.length != 0 && registerInfo[cfgName].seriesIdxs[i].type == "line" && registerInfo[cfgName].seriesIdxs[i].preDotTime == 0) {
_.each(buffer, function(obj) {
chart.add(index, [obj.ts, obj.dot])
registerInfo[cfgName].seriesIdxs[i].preDotTime = obj.ts
})
} else if (buffer && buffer.length != 0 && registerInfo[cfgName].seriesIdxs[i].type == "flag" && registerInfo[cfgName].seriesIdxs[i].preFlagTime == 0) {
_.each(buffer, function(obj) {
chart.add(index, obj.data)
registerInfo[cfgName].seriesIdxs[i].preFlagTime = obj.ts
})
}
}
}
}
function checkBufferLen(buffer, maxLen) {
while (buffer.length > maxLen) {
buffer.shift()
}
}
$.PlotMultRecords = function(cfgName, seriesName, records, extension) {
if (typeof(cfgName) == "undefined") {
throw "need cfgName!"
}
var index = -1
var eleIndex = -1
do {
var cfgInfo = registerInfo[cfgName]
if (typeof(cfgInfo) == "undefined") {
var cfg = {
name: cfgName,
__isStock: true,
title: {
text: cfgName
},
tooltip: {
xDateFormat: '%Y-%m-%d %H:%M:%S, %A'
},
legend: {
enabled: true,
},
plotOptions: {
candlestick: {
color: '#d75442',
upColor: '#6ba583'
}
},
rangeSelector: {
buttons: [{
type: 'hour',
count: 1,
text: '1h'
}, {
type: 'hour',
count: 3,
text: '3h'
}, {
type: 'hour',
count: 8,
text: '8h'
}, {
type: 'all',
text: 'All'
}],
selected: 2,
inputEnabled: true
},
series: [{
type: 'candlestick',
name: seriesName,
id: seriesName,
data: []
}],
}
if (typeof(extension) != "undefined") {
cfg.extension = extension
}
registerInfo[cfgName] = {
"cfgIdx": arrCfg.length,
"seriesIdxs": [{
seriesName: seriesName,
index: arrCfg.length,
type: "candlestick",
preBarTime: 0
}],
}
arrCfg.push(cfg)
updateSeriesIdx()
}
if (!chart) {
chart = Chart(arrCfg)
} else {
chart.update(arrCfg)
}
_.each(registerInfo[cfgName].seriesIdxs, function(ele, i) {
if (ele.seriesName == seriesName && ele.type == "candlestick") {
index = ele.index
eleIndex = i
}
})
if (index == -1) {
arrCfg[registerInfo[cfgName].cfgIdx].series.push({
type: 'candlestick',
name: seriesName,
id: seriesName,
data: []
})
registerInfo[cfgName].seriesIdxs.push({
seriesName: seriesName,
index: arrCfg.length,
type: "candlestick",
preBarTime: 0
})
updateSeriesIdx()
}
} while (index == -1)
for (var i = 0; i < records.length; i++) {
if (records[i].Time == registerInfo[cfgName].seriesIdxs[eleIndex].preBarTime) {
chart.add(index, [records[i].Time, records[i].Open, records[i].High, records[i].Low, records[i].Close], -1)
} else if (records[i].Time > registerInfo[cfgName].seriesIdxs[eleIndex].preBarTime) {
registerInfo[cfgName].seriesIdxs[eleIndex].preBarTime = records[i].Time
chart.add(index, [records[i].Time, records[i].Open, records[i].High, records[i].Low, records[i].Close])
}
}
return chart
}
$.PlotMultLine = function(cfgName, seriesName, dot, ts, extension) {
if (typeof(cfgName) == "undefined") {
throw "need cfgName!"
}
var index = -1
var eleIndex = -1
do {
var cfgInfo = registerInfo[cfgName]
if (typeof(cfgInfo) == "undefined") {
var cfg = {
name: cfgName,
__isStock: true,
title: {
text: cfgName
},
xAxis: {
type: 'datetime'
},
series: [{
type: 'line',
name: seriesName,
id: seriesName,
data: [],
}]
}
if (typeof(extension) != "undefined") {
cfg.extension = extension
}
registerInfo[cfgName] = {
"cfgIdx": arrCfg.length,
"seriesIdxs": [{
seriesName: seriesName,
index: arrCfg.length,
type: "line",
buffer: [],
preDotTime: 0
}],
}
arrCfg.push(cfg)
updateSeriesIdx()
}
if (!chart) {
chart = Chart(arrCfg)
} else {
chart.update(arrCfg)
}
_.each(registerInfo[cfgName].seriesIdxs, function(ele, i) {
if (ele.seriesName == seriesName && ele.type == "line") {
index = ele.index
eleIndex = i
}
})
if (index == -1) {
arrCfg[registerInfo[cfgName].cfgIdx].series.push({
type: 'line',
name: seriesName,
id: seriesName,
data: [],
})
registerInfo[cfgName].seriesIdxs.push({
seriesName: seriesName,
index: arrCfg.length,
type: "line",
buffer: [],
preDotTime: 0
})
updateSeriesIdx()
}
} while (index == -1)
if (typeof(ts) == "undefined") {
ts = new Date().getTime()
}
var buffer = registerInfo[cfgName].seriesIdxs[eleIndex].buffer
if (registerInfo[cfgName].seriesIdxs[eleIndex].preDotTime != ts) {
registerInfo[cfgName].seriesIdxs[eleIndex].preDotTime = ts
chart.add(index, [ts, dot])
buffer.push({
ts: ts,
dot: dot
})
checkBufferLen(buffer, maxBufferLen)
} else {
chart.add(index, [ts, dot], -1)
buffer[buffer.length - 1].dot = dot
}
return chart
}
$.PlotMultHLine = function(cfgName, value, label, color, style) {
if (typeof(cfgName) == "undefined" || typeof(registerInfo[cfgName]) == "undefined") {
throw "need cfgName!"
}
var cfg = arrCfg[registerInfo[cfgName].cfgIdx]
if (typeof(cfg.yAxis) == "undefined") {
cfg.yAxis = {
plotLines: []
}
} else if (typeof(cfg.yAxis.plotLines) == "undefined") {
cfg.yAxis.plotLines = []
}
var obj = {
value: value,
color: color || 'red',
width: 2,
dashStyle: style || 'Solid',
label: {
name: label || '',
text: (label + ":" + value) || '',
align: 'center'
},
}
var found = false
for (var i = 0; i < cfg.yAxis.plotLines.length; i++) {
if (cfg.yAxis.plotLines[i].label.name == label) {
cfg.yAxis.plotLines[i] = obj
found = true
}
}
if (!found) {
cfg.yAxis.plotLines.push(obj)
}
if (!chart) {
chart = Chart(arrCfg)
} else {
chart.update(arrCfg)
}
return chart
}
$.PlotMultTitle = function(cfgName, title, chartTitle) {
if (typeof(cfgName) == "undefined" || typeof(registerInfo[cfgName]) == "undefined") {
throw "need cfgName!"
}
var cfg = arrCfg[registerInfo[cfgName].cfgIdx]
cfg.subtitle = {
text: title
}
if (typeof(chartTitle) !== 'undefined') {
cfg.title = {
text: chartTitle
}
}
if (chart) {
chart.update(arrCfg)
}
return chart
}
$.PlotMultFlag = function(cfgName, seriesName, ts, text, title, shape, color, onSeriesName) {
if (typeof(cfgName) == "undefined" || typeof(registerInfo[cfgName]) == "undefined") {
throw "need cfgName!"
}
var index = -1
var eleIndex = -1
do {
if (!chart) {
chart = Chart(arrCfg)
} else {
chart.update(arrCfg)
}
_.each(registerInfo[cfgName].seriesIdxs, function(ele, i) {
if (ele.seriesName == seriesName && ele.type == "flag") {
index = ele.index
eleIndex = i
}
})
if (index == -1) {
arrCfg[registerInfo[cfgName].cfgIdx].series.push({
type: 'flags',
name: seriesName,
onSeries: onSeriesName || arrCfg[registerInfo[cfgName].cfgIdx].series[0].id,
data: []
})
registerInfo[cfgName].seriesIdxs.push({
seriesName: seriesName,
index: arrCfg.length,
type: "flag",
buffer: [],
preFlagTime: 0
})
updateSeriesIdx()
}
} while (index == -1)
if (typeof(ts) == "undefined") {
ts = new Date().getTime()
}
var buffer = registerInfo[cfgName].seriesIdxs[eleIndex].buffer
var obj = {
x: ts,
color: color,
shape: shape,
title: title,
text: text
}
if (registerInfo[cfgName].seriesIdxs[eleIndex].preFlagTime != ts) {
registerInfo[cfgName].seriesIdxs[eleIndex].preFlagTime = ts
chart.add(index, obj)
buffer.push({
ts: ts,
data: obj
})
checkBufferLen(buffer, maxBufferLen)
} else {
chart.add(index, obj, -1)
buffer[buffer.length - 1].data = obj
}
return chart
}
$.GetArrCfg = function() {
return arrCfg
}
$.removeChart = function(cfgName) {
var index = -1
for (var i = 0; i < arrCfg.length; i++) {
if (arrCfg[i].name == cfgName) {
index = i
break
}
}
if (index != -1) {
arrCfg.splice(index, 1)
}
if (typeof(registerInfo[cfgName]) != "undefined") {
delete registerInfo[cfgName]
}
updateSeriesIdx()
}
function init() {
if (isChartReset) {
Log("重置图表", "#FF0000")
chart = Chart(arrCfg)
chart.reset()
Log("清空持久化数据,key:", "registerInfo、arrCfg #FF0000")
_G("registerInfo", null)
_G("arrCfg", null)
} else {
var multChartRegisterInfo = _G("registerInfo")
var multChartArrCfg = _G("arrCfg")
if (multChartRegisterInfo && multChartArrCfg) {
registerInfo = multChartRegisterInfo
arrCfg = multChartArrCfg
Log("恢复 registerInfo、arrCfg #FF0000")
} else {
Log("没有数据可以恢复 #FF0000")
}
}
}
function onexit() {
_G("registerInfo", registerInfo)
_G("arrCfg", arrCfg)
Log("保存数据,key : registerInfo, arrCfg #FF0000")
}
// test
function main() {
LogReset(10)
var i = 0
var prePrintTs = 0
var t = _C(exchange.GetTicker)
while (true) {
var r = _C(exchange.GetRecords)
$.PlotMultRecords("chart1", "kline1", r, {
layout: 'single',
col: 6,
height: '600px'
})
$.PlotMultRecords("chart2", "kline2", r, {
layout: 'single',
col: 6,
height: '600px'
})
$.PlotMultLine("chart2", "line1", t.Last, r[r.length - 1].Time)
$.PlotMultLine("chart3", "line2", 10 + i)
$.PlotMultLine("chart6", "line6", 100 + i)
$.PlotMultLine("chart4", "line3", 1000 + i, new Date().getTime(), {
layout: 'single',
col: 4,
height: '300px'
})
$.PlotMultLine("chart5", "line4", 10000 + i, new Date().getTime(), {
layout: 'single',
col: 8,
height: '300px'
})
$.PlotMultHLine("chart1", r[r.length - 1].Close, "HLine1", "blue", "ShortDot")
$.PlotMultHLine("chart4", t.Sell, "HLine2", "green")
$.PlotMultTitle("chart3", "change : chart3->test1", "test1")
var ts = new Date().getTime()
if (ts - prePrintTs > 1000 * 20) {
prePrintTs = ts
$.PlotMultFlag("chart3", "flag1", new Date().getTime(), "flag test" + i, "flag1")
}
if (i == 10) {
Log("i == 3")
$.PlotMultFlag("chart4", "flag2", new Date().getTime(), "flag test" + i, "flag2")
$.PlotMultFlag("chart1", "flag3", new Date().getTime(), "flag test" + i, "flag3", "squarepin", "green", "kline1")
} else if (i == 20) {
Log("i == 8")
$.PlotMultLine("chart1", "line5", t.Last, r[r.length - 1].Time)
} else if (i == 30) {
Log("i == 10")
$.PlotMultFlag("chart2", "flag4", new Date().getTime(), "flag test" + i, "flag4", "circlepin", "black", "kline2")
$.removeChart("chart1")
}
i++
Sleep(1000 * 1)
}
}
Alamat strategi: https://www.fmz.com/strategy/353264
Di sini saya hanya memberikan beberapa ide. Jika Anda tertarik, Anda dapat terus menambahkan jenis grafik yang didukung dan terus meningkatkannya, seperti menggambar grafik kedalaman pasar, grafik batang, grafik pai, dll.