I want to create a macro like this
var diffLength =
| index1 === 0 then xPos[index1]
| index1 === 2 then (xPos[index1] - xPos[index1 - 1]) * focusFactor
| otherwise xPos[index1] - xPos[index1 - 1]
which should expand like :
var diffLength =
index1 === 0 ? xPos[index1] :
index1 === 2 ? (xPos[index1] - xPos[index1 - 1]) * focusFactor :
xPos[index1] - xPos[index1 - 1];
SweetJS code :
macro |{
rule {
$cond:expr then $check:expr $($guard:(|) $restCond:expr then $restCheck:expr) ... $lastGuard:(|) otherwise $lastCheck:expr
} => {
( $cond ? $check : $($restCond ? $restCheck :) ... $lastCheck )
}
}
which works only if I change $guards:(h) and $lastGuard:(h) insteed of $guards:(|) and $lastGuard:(|) and actual code like
var diffLength =
| index1 === 0 then xPos[index1]
h index1 === 2 then (xPos[index1] - xPos[index1 - 1]) * focusFactor
h otherwise xPos[index1] - xPos[index1 - 1]
Reason is I am unable to stop sweetjs to parse the adjacent "|"(pipe) delimiters.
Can anyone suggest how can I do it?
Related
Firstly thanks for any help its a bit of a complex question!
I have a hobby of converting pinescript scripts to javascript which i then use to run through a backtester infra i built in js. Just to start i am doing this with many scripts successfully, the problem wont be that im sending candles wrong or something.
I am 95% sure that my problem lies within not doing the ATR correct. I have messed with this function a bit and get a little close but not exact. Im pretty sure i converted the supertrend part correct though.
Lets start with the pinescript script of supertrend by KivancOzbilgic:
//#version=4
study("Supertrend", overlay = true, format=format.price, precision=2, resolution="")
Periods = input(title="ATR Period", type=input.integer, defval=10)
src = input(hl2, title="Source")
Multiplier = input(title="ATR Multiplier", type=input.float, step=0.1, defval=3.0)
changeATR= input(title="Change ATR Calculation Method ?", type=input.bool, defval=true)
showsignals = input(title="Show Buy/Sell Signals ?", type=input.bool, defval=true)
highlighting = input(title="Highlighter On/Off ?", type=input.bool, defval=true)
atr2 = sma(tr, Periods)
atr= changeATR ? atr(Periods) : atr2
up=src-(Multiplier*atr)
up1 = nz(up[1],up)
up := close[1] > up1 ? max(up,up1) : up
dn=src+(Multiplier*atr)
dn1 = nz(dn[1], dn)
dn := close[1] < dn1 ? min(dn, dn1) : dn
trend = 1
trend := nz(trend[1], trend)
trend := trend == -1 and close > dn1 ? 1 : trend == 1 and close < up1 ? -1 : trend
upPlot = plot(trend == 1 ? up : na, title="Up Trend", style=plot.style_linebr, linewidth=2, color=color.green)
buySignal = trend == 1 and trend[1] == -1
plotshape(buySignal ? up : na, title="UpTrend Begins", location=location.absolute, style=shape.circle, size=size.tiny, color=color.green, transp=0)
plotshape(buySignal and showsignals ? up : na, title="Buy", text="Buy", location=location.absolute, style=shape.labelup, size=size.tiny, color=color.green, textcolor=color.white, transp=0)
dnPlot = plot(trend == 1 ? na : dn, title="Down Trend", style=plot.style_linebr, linewidth=2, color=color.red)
sellSignal = trend == -1 and trend[1] == 1
plotshape(sellSignal ? dn : na, title="DownTrend Begins", location=location.absolute, style=shape.circle, size=size.tiny, color=color.red, transp=0)
plotshape(sellSignal and showsignals ? dn : na, title="Sell", text="Sell", location=location.absolute, style=shape.labeldown, size=size.tiny, color=color.red, textcolor=color.white, transp=0)
mPlot = plot(ohlc4, title="", style=plot.style_circles, linewidth=0)
longFillColor = highlighting ? (trend == 1 ? color.green : color.white) : color.white
shortFillColor = highlighting ? (trend == -1 ? color.red : color.white) : color.white
fill(mPlot, upPlot, title="UpTrend Highligter", color=longFillColor)
fill(mPlot, dnPlot, title="DownTrend Highligter", color=shortFillColor)
alertcondition(buySignal, title="SuperTrend Buy", message="SuperTrend Buy!")
alertcondition(sellSignal, title="SuperTrend Sell", message="SuperTrend Sell!")
changeCond = trend != trend[1]
alertcondition(changeCond, title="SuperTrend Direction Change", message="SuperTrend has changed direction!")
Here is my implementation in javascript
// candles example (I provide 100 candles)
const candles = [{high: 10, low: 8, close: 9, open: 8.5}, ...]
static ATR = async (candles, multiplier, limit) => {
const lows = candles.map((candle) => +candle.low)
const highs = candles.map((candle) => +candle.high)
const closes = candles.map((candle) => +candle.close)
let TRResults = []
for (let x = 1; x < candles.length; x++) TRResults.push(Math.max(highs[x] - lows[x], Math.abs(highs[x] - closes[x - 1]), Math.abs(lows[x] - closes[x - 1])))
let RMA_TR_Results = [TRResults[0]]
const alpha = 1 / limit
for (let x = 1; x < TRResults.length; x++) RMA_TR_Results.push((alpha * TRResults[x]) + ((1 - alpha) * RMA_TR_Results[RMA_TR_Results.length - 1]))
return RMA_TR_Results[RMA_TR_Results.length - 1] * multiplier
}
static superTrend = async(candles, multiplier, limit) => {
let upperBands = []
let lowerBands = []
let superTrends = []
for (let i = 0; i < candles.length; i++) {
if (i >= limit * 4) {
const lastCandle = +candles[i - 1].close
const currentCandling = +candles[i].close
const candlesATR = await this.ATR(candles.slice(i - (limit * 4), limit * 4), multiplier, limit)
const basicUpperBand = ((+candles[i].high + +candles[i].low) / 2) - candlesATR
const basicLowerBand = ((+candles[i].high + +candles[i].low) / 2) + candlesATR
if (i === limit * 4) {
upperBands.push(basicUpperBand)
lowerBands.push(basicLowerBand)
superTrends.push(true)
} else {
const lastUpperBand = upperBands[upperBands.length - 1]
const lastLowerBand = lowerBands[lowerBands.length - 1]
upperBands.push(lastCandle > lastUpperBand ? Math.max(basicUpperBand, lastUpperBand) : basicUpperBand)
lowerBands.push(lastCandle < lastLowerBand ? Math.min(basicLowerBand, lastLowerBand) : basicLowerBand)
const lastSuperTrend = superTrends[superTrends.length - 1]
superTrends.push(!lastSuperTrend && currentCandling > lastLowerBand ? true : lastSuperTrend && currentCandling < lastUpperBand ? false : lastSuperTrend)
}
}
}
return superTrends[superTrends.length - 1]
}
// Running the super trend
const supertrendResult = await superTrend(candles, 2, 14)
Again any help is appreciated!
Heres some more resources i am using:
RMA Calculation (in pinescript)
pine_rma(source, length) =>
alpha = 1 / length
sum = 0.0
sum := na(sum[1]) ?
ta.sma(source, length) :
alpha * source + (1 - alpha) * nz(sum[1])
plot(pine_rma(close, 15))
TR Calculation
true range = max[(high - low), abs(high - previous close), abs (low - previous close)]
I found my problem. Its with the way did the splice
const candlesATR = await this.ATR(candles.slice(i - (limit * 4), limit * 4), multiplier, limit)
Should be:
const candlesATR = await this.ATR(candles.slice(i - (limit * 4), i), multiplier, limit)
//not the answer I want
var recur = (n, m) => {
if (n || m === 1) {
return 1;
} else {
return recur(n - 1, m) + recur(n, m - 1);
}
};
//answer I want
var recur2 = (n, m) => {
return 1 ? n || m === 1 : recur2(n - 1, m) + recur2(n, m - 1);
};
console.log(recur(2, 2));
console.log(recur(3, 3));
console.log(recur2(2, 2));
console.log(recur2(3, 3));
Results :
I am confused about the difference in answers. What's the difference in using conditional operator? I thought they were the same beside shorter syntax?
You have different logical operators in top and bottom functions. For the recur2 to work the same as recur you need to change this:
return 1 ? n || m === 1 : recur2(n - 1, m) + recur2(n, m - 1);
to:
return n || m === 1 ? 1 : recur2(n - 1, m) + recur2(n, m - 1);
In your example 1 is always truthy so, regardless of what arguments you pass there it returns the result of n || m === 1 which is n.
The below should work,
var recur2 = (n, m) => {
return n || m === 1 ? 1 : recur2(n - 1, m) + recur2(n, m - 1);
};
console.log(recur2(2, 2));
console.log(recur2(3, 3));
This is how comparision works:
console.log(2||0)
console.log(0||1)
console.log(0||null)
console.log(Boolean(0||1))
The || operator will return the first truthy value or else the second value.
They work inside the if(), because these are all truthy values : 1,2, "11" etc.
null, 0 etc. are falsy values.
In your first code, it auto returns from the first condition with 1 in both cases.
Should point out that in conditional operator the expression before ? is checked and if true first expression is returned else the second.
In your second code 1 ? n || m === 1: 1 is a truthy value so first condition will run always.
As mentioned above : (n || m === 1) will return n if it is truthy, or else will return the value of the expression m===1.
The correct code using conditional operator could be :
return (n || m === 1) ? 1 : recur2(n - 1, m) + recur2(n, m - 1);
Thank you ischenkodv for pointing out the error and everyone for your kindness. I just found out I made a terrible mistake by assuming n || m === 1 equals to n === 1 || m === 1. Correcting this solved the problem.
var recur = (n, m) => {
if (n === 1 || m === 1) {
return 1;
} else {
return recur(n - 1, m) + recur(n, m - 1);
}
};
var recur2 = (n, m) => {
return n === 1 || m === 1 ? 1 : recur2(n - 1, m) + recur2(n, m - 1);
};
console.log(recur(2, 2));
console.log(recur(3, 3));
console.log(recur2(2, 2));
console.log(recur2(3, 3));
Description
I'm trying to implement a JS version of Levenshtein distance function, using the matrix method described on this page in Wikipedia.
Problem
The algorithm works as expected, it returns the difference between the strings (the amount of edits you need to do for strings to be equal), except it ignores index 0, no matter what character is at index 0, it always considers it to be "correct":
levenshteinDistance('cat', 'cave') // 2 (correct)
levenshteinDistance('cat', 'cap') // 1 (correct)
levenshteinDistance('cat', 'hat') // 0 (should be 1)
levenshteinDistance('cat', 'rat') // 0 (should be 1)
levenshteinDistance('cat', 'bat') // 0 (should be 1)
Code
https://codepen.io/aQW5z9fe/pen/mdPvJqV?editors=0011
function levenshteinDistance (string1, string2, options) {
if (string1 === string2) { return 0 }
let matrix = []
let cost
let i
let j
// Init first column of each row
for (i = 0; i <= string1.length; i++) {
matrix[i] = [i]
}
// Init each column in the first row
for (j = 0; j <= string2.length; j++) {
matrix[0][j] = j
}
// Fill in the rest of the matrix
for (i = 1; i <= string1.length; i++) {
for (j = 1; j <= string2.length; j++) {
// Set cost
cost = string1[i] === string2[j]
? 0
: 1
// Set the distances
matrix[i][j] = Math.min(
matrix[i - 1][j] + 1, // deletion
matrix[i][j - 1] + 1, // insertion
matrix[i - 1][j - 1] + cost // substitution
)
if (
options.allowTypos &&
i > 1 &&
j > 1 &&
string1[i] === string2[j - 1] &&
string1[i - 1] === string2[j]
) {
matrix[i][j] = Math.min(
matrix[i][j],
matrix[i - 2][j - 2] + 1
) // transposition
}
}
}
return matrix[string1.length][string2.length]
}
console.log(
levenshteinDistance('cat', 'hat', { allowTypos: true })
)
I think you just made a small mistake I think this:
cost = string1[i] === string2[j]
Should be :
cost = string1[i-1] === string2[j-1]
Since otherwise you never check for the cost of the first letter in the strings and the cost for the letters after that in case of the substitution is always derived from that.
EDIT:
The part inside the transpose section/ allow typo section should also be changed from:
string1[i] === string2[j - 1] &&
string1[i - 1] === string2[j]
to
string1[i-1] === string2[j - 2] &&
string1[i - 2] === string2[j-1]
After looking at the Wikipedia article they for some reason use 1 indexed arrays for the strings and 0 indexed arrays for the matrix, so I guess that was the root of the problem.
Code challenge: write a function that gets the middle letter(s) of a string of even or odd numbered letters, as a ternary operator.
My function is working for odd numbers. But it does not work for even numbers - it seems to be skipping letters.
eg.
getMiddle("testing") // the output is "t", this is correct.
getMiddle("test") // the output is "et", it should be "es".
my code:
function getMiddle(str) {
return str.length % 2 === 0 ? str[str.length/2 - 1] + str[str.length/2 + 1] : str[Math.floor(str.length/2)];
}
When the length is is even, you want the 2 characters which are at the middle. You do that by taking the length of the string and divide it by 2.
That index in a zero based array will be the s.If you subtract 1 from the index, it will be the e. When you add +1, you get the t
In your code, you concatenate the index -1 and the index +1 leading to et
You should omit the + 1 in str[str.length/2 + 1] like:
function getMiddle(str) {
return str.length % 2 === 0 ? str[str.length / 2 - 1] + str[str.length / 2] : str[Math.floor(str.length / 2)];
}
function getMiddle(str) {
return str.length % 2 === 0 ? str[str.length / 2 - 1] + str[str.length / 2] : str[Math.floor(str.length / 2)];
}
console.log(getMiddle("testing"));
console.log(getMiddle("test"));
console.log(getMiddle("testtest"))
I understand a use of ternary is required but you may simply do this without any such conditionals as well.
var getmid = (s, i=s.length/2) => s.slice(Math.ceil(i-1), Math.ceil(i+1)-(s.length & 1));
console.log(getmid("test")); // <- "es"
console.log(getmid("testo")); // <- "s"
I'm working on a function that should take information about monthly mortgage payment amount, interest rate, downpayment, etc. and spit out the cost of home that the user could hypothetically afford.
The formula (I think...) is this:
And I have it in JS like this:
function formatMoney(number, c, d, t) {
var n = number,
c = isNaN(c = Math.abs(c)) ? 2 : c,
d = d == undefined ? "." : d,
t = t == undefined ? "," : t,
s = n < 0 ? "-" : "",
i = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(c))),
j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
};
function calculateCost()
{
var cost = downpayment + ( monthly * ( Math.pow( 1 + ( interest / 12 ), term * 12 ) - 1 ) / ( ( interest / 12 ) * ( Math.pow( 1 + ( interest / 12 ), term * 12 ) ) ) );
cost = "$" + formatMoney(cost, 2, ".", ",")
return cost;
}
But it's spitting out answers that are way too big to be logical. Can anyone familiar with JS figure out where I'm going wrong, translating the formula to JS?