During the technical analysis in trading, traders all take stock price data as normally distributed data to analyze and study. However, the stock price data distribution does not conform to the standard normal distribution. Fisher Transformation
is a method that can transform price data into something similar to a normal distribution. Fisher Transformation
smoothes the market data and removes some sharp small periodic vibrations. Trading signals can be sent using the interleaving of today's and previous day's indicators.
There are so many references about Fisher Transformation
on Baidu and Zhihu, which will not be explained here in details.
Indicator Algorithm:
- Today's median price:
mid=(low + high) / 2
- Confirm the calculation period; you can use 10 days a period. Calculate the highest price and the lowest price in the period:
lowestLow = the lowest price in the period
,highestHigh = the highest price in the period
. - Define price change parameter (in which
ratio
is a constant from 0 to 1; for example, you can choose 0.5 or 0.33):( /upload/asset/269119678f29cb8e19783.png - Apply
Fisher
transformation to the price change parameterx
, and theFisher
indicator can be obtained: /upload/asset/2688d747d6b9ca2efee21.png
Use JavaScript to Realize the Algorithm
According to the indicator algorithm, realize it step by step. It should be noted that this algorithm is an iterative algorithm, and for preX
, preFish
, they are initially set to 0. Math.log
is the logarithm based on the natural constant e In addition, the modification of x is not mentioned in the above algorithm, and I almost ignored this problem during writing:
Modify the value of x; if the value is over 0.99, forcibly set to 0.999; if it is less than -0.99, set to -0.999.
if (x > 0.99) { x = 0.999 } else if (x < -0.99) { x = -0.999 }
This is the first time I see the algorithm and the indicator, after porting it according to the algorithm. I have not verified the implementation, and students who are interested in research can verify whether there are any errors. Thanks a lot for pointing out errors, if there are any.
Source code of Fisher Transform
indicator algorithm:
function getHighest(arr, period) { if (arr.length == 0 || arr.length - period < 0) { return null } var beginIndex = arr.length - period var ret = arr[beginIndex].High for (var i = 0 ; i < arr.length - 1 ; i++) { if (arr[i + 1].High > ret) { ret = arr[i + 1].High } } return ret } function getLowest(arr, period) { if (arr.length == 0 || arr.length - period < 0) { return null } var beginIndex = arr.length - period var ret = arr[beginIndex].Low for (var i = 0 ; i < arr.length - 1 ; i++) { if (arr[i + 1].Low < ret) { ret = arr[i + 1].Low } } return ret } function calcFisher(records, ratio, period) { var preFish = 0 var preX = 0 var arrFish = [] // when the K-line length is not long enough to meet the K-line period if (records.length < period) { for (var i = 0 ; i < records.length ; i++) { arrFish.push(0) } return arrFish } // traverse K-lines for (var i = 0 ; i < records.length ; i++) { var fish = 0 var x = 0 var bar = records[i] var mid = (bar.High + bar.Low) / 2 // when the current BAR is not enough for period to calculate if (i < period - 1) { fish = 0 preFish = 0 arrFish.push(fish) continue } // calculate the highest price and the lowest price in the period var bars = [] for (var j = 0 ; j <= i ; j++) { bars.push(records[j]) } var lowestLow = getLowest(bars, period) var highestHigh = getHighest(bars, period) // price change parameter x x = ratio * 2 * ((mid - lowestLow) / (highestHigh - lowestLow) - 0.5) + (1 - ratio) * preX if (x > 0.99) { x = 0.999 } else if (x < -0.99) { x = -0.999 } preX = x fish = 0.5 * Math.log((1 + x) / (1 - x)) + 0.5 * preFish preFish = fish arrFish.push(fish) } return arrFish }
Plot
It is very easy to plot on FMZ; you can refer to a lot of examples in the strategy square: https://www.fmz.com/square
, and you can also search for the strategies you need.
var cfg = { // used to initially configure the chart objects (namely chart settings) plotOptions: { candlestick: { color: '#d75442', // color value upColor: '#6ba583' // color vlaue } }, title: { text: 'Fisher Transform'}, //title subtitle: {text: ''}, //subtitle plotOptions: { candlestick: { tooltip: { pointFormat: '<span style="color:{point.color}">\u25CF</span> <b> {series.name}</b><br/>' + 'open: {point.open}<br/>' + 'highest: {point.high}<br/>' + 'lowest: {point.low}<br/>' + 'close: {point.close}<br/>' } } }, yAxis: [{ title: { text: 'K-line market quote' }, height: '70%', lineWidth: 1 }, { title: { text: 'Fisher Transform' }, top: '75%', height: '30%', offset: 0, lineWidth: 1 }], series: [//series { type: 'candlestick', yAxis: 0, name: 'K-line', id: 'KLine', // control the candlestick color of fall color: 'green', lineColor: 'green', // control the candlestick color of rise upColor: 'red', upLineColor: 'red', data: [] },{ type: 'line', // set the type of the current data series as: line yAxis: 1, // the y axis for use is the y axis with index 0 (in highcharts, there can be multiple y axis, and here it indicates the y axis with index 0) showInLegend: true, // name: 'fish', // set according the parameter label passed by the function lineWidth: 1, data: [], // data item of the data series tooltip: { // tip for tool valueDecimals: 2 // the decimals of the value reserve 5 } },{ type: 'line', // set the type of the current data series as: line yAxis: 1, // the y axis for use is the y axis with index 0 (in highcharts, there can be multiple y axis, and here it indicates the y axis with index 0) showInLegend: true, // name: 'preFish', // set according the parameter label passed by the function lineWidth: 1, data: [], // data item of the data series tooltip: { // tip for tool valueDecimals: 2 // the decimals of the value reserve 5 } } ] } var chart = Chart(cfg) function main() { var ts = 0 chart.reset() while (true) { var r = exchange.GetRecords() var fisher = calcFisher(r, 0.33, 10) if (!r || !fisher) { Sleep(500) continue } for (var i = 0; i < r.length; i++){ if (ts == r[i].Time) { chart.add([0,[r[i].Time, r[i].Open, r[i].High, r[i].Low, r[i].Close], -1]) chart.add([1,[r[i].Time, fisher[i]], -1]) if (i - 1 >= 0) { chart.add([2,[r[i].Time, fisher[i - 1]], -1]) } }else if (ts < r[i].Time) { chart.add([0,[r[i].Time, r[i].Open, r[i].High, r[i].Low, r[i].Close]]) chart.add([1,[r[i].Time, fisher[i]]]) if (i - 1 >= 0) { chart.add([2,[r[i].Time, fisher[i - 1]]]) } ts = r[i].Time } } } }
/upload/asset/16f1eb0ec7efad8c664a.png
Therefore, it is very convenient to study data, chart display and strategy design on FMZ.
Here I start the discussion for more ideas, so welcome teachers and students here to leave comments.