fix: payoff regex (\d stripped to d), proper fill zones, canvas annotation plugin
This commit is contained in:
parent
4b0bfb2a12
commit
c9a38be908
1 changed files with 68 additions and 54 deletions
|
|
@ -405,18 +405,17 @@ function toggleCard(id){
|
|||
let payoffChartInst = null;
|
||||
|
||||
function parseOptionSym(sym) {
|
||||
// Angel format: UNDERLYING + YY + M(1digit) + DD + STRIKE + CE/PE
|
||||
// e.g. SENSEX2651479000CE → underlying=SENSEX, yy=26, m=5, dd=14, strike=79000, type=CE
|
||||
let m = sym.match(/^([A-Z]+)(d{2})(d{1})(d{2})(d+)(CE|PE)$/);
|
||||
var RE1 = new RegExp("^([A-Z]+)(\\d{2})(\\d{1})(\\d{2})(\\d+)(CE|PE)$");
|
||||
var m = sym.match(RE1);
|
||||
if (m) {
|
||||
const exp = new Date(`20${m[2]}-${m[3].padStart(2,'0')}-${m[4]}`);
|
||||
return { underlying: m[1], strike: parseInt(m[5]), type: m[6], expiry: exp };
|
||||
var exp = new Date(20+m[2]+-+m[3].padStart(2,0)+-+m[4]);
|
||||
return { underlying: m[1], strike: parseInt(m[5]), type: m[6], expiry: isNaN(exp)?null:exp };
|
||||
}
|
||||
// Fallback: UNDERLYING + YYMMDD + STRIKE + CE/PE (2-digit month)
|
||||
m = sym.match(/^([A-Z]+)(d{2})(d{2})(d{2})(d+)(CE|PE)$/);
|
||||
var RE2 = new RegExp("^([A-Z]+)(\\d{2})(\\d{2})(\\d{2})(\\d+)(CE|PE)$");
|
||||
m = sym.match(RE2);
|
||||
if (m) {
|
||||
const exp = new Date(`20${m[2]}-${m[3]}-${m[4]}`);
|
||||
return { underlying: m[1], strike: parseInt(m[5]), type: m[6], expiry: exp };
|
||||
var exp2 = new Date(20+m[2]+-+m[3]+-+m[4]);
|
||||
return { underlying: m[1], strike: parseInt(m[5]), type: m[6], expiry: isNaN(exp2)?null:exp2 };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -530,51 +529,15 @@ async function loadPayoff() {
|
|||
const gc = dk ? 'rgba(255,255,255,.05)' : 'rgba(0,0,0,.05)';
|
||||
const tc = dk ? '#3D444D' : '#C4B8B0';
|
||||
|
||||
// Profit fill (above zero) and loss fill (below zero) — use two datasets with clip trick
|
||||
const profitData = ys.map(y => ({ y: Math.max(y, 0) }));
|
||||
const lossData = ys.map(y => ({ y: Math.min(y, 0) }));
|
||||
|
||||
canvas._beLines = breakevens; canvas._spotLine = spot; canvas._chartXs = xs;
|
||||
if (payoffChartInst) payoffChartInst.destroy();
|
||||
|
||||
const annotations = {};
|
||||
// Breakeven vertical lines
|
||||
breakevens.forEach((be, i) => {
|
||||
annotations['be'+i] = {
|
||||
type: 'line', xMin: be, xMax: be,
|
||||
borderColor: 'rgba(245,166,35,.7)', borderWidth: 1.5, borderDash: [5,4],
|
||||
label: { display: true, content: be.toLocaleString('en-IN'), position: 'start',
|
||||
color: '#F5A623', font: { size: 10, family: 'Geist Mono' }, yAdjust: -8 }
|
||||
};
|
||||
});
|
||||
// Current spot
|
||||
if (spot) {
|
||||
annotations['spot'] = {
|
||||
type: 'line', xMin: spot, xMax: spot,
|
||||
borderColor: 'rgba(255,107,74,.8)', borderWidth: 2, borderDash: [6,3],
|
||||
label: { display: true, content: spot.toLocaleString('en-IN'), position: 'end',
|
||||
color: '#FF6B4A', font: { size: 10, family: 'Geist Mono' }, yAdjust: 8 }
|
||||
};
|
||||
}
|
||||
|
||||
payoffChartInst = new Chart(canvas, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: xs,
|
||||
datasets: [
|
||||
{
|
||||
label: 'Profit',
|
||||
data: ys,
|
||||
borderColor: ys[Math.floor(ys.length/2)] >= 0 ? '#2ECC71' : '#E74C3C',
|
||||
borderWidth: 2.5,
|
||||
tension: 0,
|
||||
pointRadius: 0,
|
||||
fill: {
|
||||
target: { value: 0 },
|
||||
above: 'rgba(46,204,113,0.15)',
|
||||
below: 'rgba(231,76,60,0.15)',
|
||||
},
|
||||
},
|
||||
],
|
||||
data: { labels: xs, datasets: [
|
||||
{label:'Profit Zone',data:ys.map(function(y){return y>=0?y:0;}),borderColor:'transparent',backgroundColor:'rgba(46,204,113,0.18)',tension:0,pointRadius:0,fill:true},
|
||||
{label:'Loss Zone',data:ys.map(function(y){return y<0?y:0;}),borderColor:'transparent',backgroundColor:'rgba(231,76,60,0.18)',tension:0,pointRadius:0,fill:true},
|
||||
{label:'P&L',data:ys,borderColor:'#FF6B4A',borderWidth:2.5,tension:0,pointRadius:0,fill:false},
|
||||
] },
|
||||
},
|
||||
options: {
|
||||
responsive: true, maintainAspectRatio: false, animation: false,
|
||||
|
|
@ -594,9 +557,6 @@ async function loadPayoff() {
|
|||
},
|
||||
},
|
||||
},
|
||||
annotation: (window.ChartAnnotation && {
|
||||
annotations,
|
||||
}),
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
|
|
@ -620,6 +580,60 @@ async function loadPayoff() {
|
|||
}
|
||||
// End payoff graph
|
||||
|
||||
|
||||
var _payoffPlugin = {
|
||||
id: 'payoffLines',
|
||||
afterDraw: function(chart) {
|
||||
if (!chart.canvas || !chart.canvas._beLines) return;
|
||||
var ctx = chart.ctx;
|
||||
var xs = chart.canvas._chartXs;
|
||||
if (!xs || !xs.length) return;
|
||||
var xScale = chart.scales.x, yScale = chart.scales.y;
|
||||
var lo = xs[0], hi = xs[xs.length-1], range = hi - lo;
|
||||
if (!range) return;
|
||||
function xPx(v) { return xScale.left + (v-lo)/range*(xScale.right-xScale.left); }
|
||||
ctx.save();
|
||||
// Breakeven lines — amber dashed
|
||||
(chart.canvas._beLines || []).forEach(function(be) {
|
||||
var x = xPx(be);
|
||||
if (x < xScale.left || x > xScale.right) return;
|
||||
ctx.beginPath();
|
||||
ctx.setLineDash([5,4]);
|
||||
ctx.strokeStyle = 'rgba(245,166,35,0.85)';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.moveTo(x, yScale.top);
|
||||
ctx.lineTo(x, yScale.bottom);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
ctx.fillStyle = '#F5A623';
|
||||
ctx.font = '9px monospace';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(Number(be).toLocaleString('en-IN'), x, yScale.top + 10);
|
||||
});
|
||||
// Spot line — coral dashed
|
||||
var spot = chart.canvas._spotLine;
|
||||
if (spot) {
|
||||
var x = xPx(spot);
|
||||
if (x >= xScale.left && x <= xScale.right) {
|
||||
ctx.beginPath();
|
||||
ctx.setLineDash([6,3]);
|
||||
ctx.strokeStyle = 'rgba(255,107,74,0.9)';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.moveTo(x, yScale.top);
|
||||
ctx.lineTo(x, yScale.bottom);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
ctx.fillStyle = '#FF6B4A';
|
||||
ctx.font = 'bold 9px monospace';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('Spot ' + Number(spot).toLocaleString('en-IN'), x, yScale.bottom - 4);
|
||||
}
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
};
|
||||
Chart.register(_payoffPlugin);
|
||||
|
||||
loadConfig();refresh();
|
||||
setInterval(refresh,60000);
|
||||
setInterval(loadMarket,15000);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue