Skip to content

Commit

Permalink
HBS-0: input pine optimization to nyc copy
Browse files Browse the repository at this point in the history
  • Loading branch information
stimofeev-tv committed Feb 16, 2024
1 parent 0631bef commit a5149d5
Show file tree
Hide file tree
Showing 24 changed files with 1,576 additions and 1,523 deletions.
133 changes: 133 additions & 0 deletions BEST_PRACTICES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Рекомендации по написанию эффективного кода на пайне

### По-возможности обращаться непосредственно к истории серий (`time`/`open`/`high`/`close`) вместо обращения к истории переменных или аргументов, в противном случае на каждый вызов функции будет выделен буфер в размере глубины обращения. В частности, если функция всегда вызывается с некоторыми одинаковыми параметрами, их следует инлайнить
```
fastSearchN(_xs, x, maxbarsback) => // xs - sorted, ascending
xs = _xs
if bar_index == 0
xs += xs[maxbarsback] * 0 // max_bars_back
left = 0
right = math.min(bar_index, maxbarsback)
mid = 0
if xs < x
0
else
for i = 0 to 9 by 1
mid := math.ceil((left + right) / 2)
if left == right
break
else if xs[mid] < x
right := mid
continue
else if xs[mid] > x
left := mid
continue
else
break
mid
countOfBars1DayAgoBond = fastSearchTimeIndex(dayAgoYield, dayYield)
countOfBars1MonthAgoBond = fastSearchTimeIndex(monthAgoYield, monthYield)
countOfBars1YearAgoBond = fastSearchTimeIndex(yearAgoYield, yearYield)
```
можно улучшить так
```
fastSearchTimeIndex(x, maxbarsback) =>
max_bars_back(time, maxbarsback)
left = 0
right = math.min(bar_index, maxbarsback)
mid = 0
if time < x
0
else
for i = 0 to 9 by 1
mid := math.ceil((left + right) / 2)
if left == right
break
else if time[mid] < x
right := mid
continue
else if time[mid] > x
left := mid
continue
else
break
mid
countOfBars1DayAgoBond = fastSearchTimeIndex(dayAgoYield, dayYield)
countOfBars1MonthAgoBond = fastSearchTimeIndex(monthAgoYield, monthYield)
countOfBars1YearAgoBond = fastSearchTimeIndex(yearAgoYield, yearYield)
```
### Рекомендуется схлопывать одинаковые секюрити в одну при помощи тюплов
```
fund_flows1M = request.security(makeFundFlowsTicker(), getFundTF(), sum(oneMonth), ignore_invalid_symbol=true, gaps=barmerge.gaps_off)
fund_flows3M = request.security(makeFundFlowsTicker(), getFundTF(), sum(threeMonths), ignore_invalid_symbol=true, gaps=barmerge.gaps_off)
fund_flows1Y = request.security(makeFundFlowsTicker(), getFundTF(), sum(oneYear), ignore_invalid_symbol=true, gaps=barmerge.gaps_off)
fund_flows3Y = request.security(makeFundFlowsTicker(), getFundTF(), sum(threeYears), ignore_invalid_symbol=true, gaps=barmerge.gaps_off)
fund_flows5Y = request.security(makeFundFlowsTicker(), getFundTF(), sum(fiveYears), ignore_invalid_symbol=true, gaps=barmerge.gaps_off)
fund_flowsYTD = request.security(makeFundFlowsTicker(), getFundTF(), sumYTD(), ignore_invalid_symbol=true, gaps=barmerge.gaps_off)
```
стоит зарефакторить так
```
[fund_flows1M, fund_flows3M, fund_flows1Y, fund_flows3Y, fund_flows5Y, fund_flowsYTD] = request.security(fundFlowsTicker, fundTF, [sum(oneMonth), sum(threeMonths), sum(oneYear), sum(threeYears), sum(fiveYears), sumYTD()], ignore_invalid_symbol=true, gaps=barmerge.gaps_off)
```
### Следует переиспользовать вычиcления
```
plot(ta.rsi(close, 2), title='RSI2')
plot(ta.rsi(close, 2)[1], title='RSI2[1]')
```
нужно переписать так
```
RSI2 = ta.rsi(close, 2)
plot(RSI2, title='RSI2')
plot(RSI2[1], title='RSI2[1]')
```
### Стоит использовать `var` по назначению
```
pivotX_open = float(na)
pivotX_open := nz(pivotX_open[1], open)
```
можно упростить
```
var pivotX_open = open
```
### Если что-то можно посчитать 1 раз, то стоит это сделать и записать результат в var переменную. NB: если инициализируемое значение константа, то var не нужен
```
getFundTF() => timeframe.isintraday ? "1D" : timeframe.period
```
превратить в
```
var fundTF = timeframe.isintraday ? "D" : timeframe.period
```
### Эффективнее применять подход "вычислений по скользящему окну" вместо постоянного обхода в цикле
```
sumYTD()=>
max_bars_back(time, 2*oneYear)
max_bars_back(close, 2*oneYear)
var firstBar = time
if year(timenow, syminfo.timezone) == year(firstBar, syminfo.timezone)
na
else
sum = 0.
for i = 0 to bar_index
if year(time[i], syminfo.timezone) < year
break
sum += close[i]
sum
```
можно соптимизировать
```
sumYTD()=>
var startYear = year(time, syminfo.timezone)
if year(timenow, syminfo.timezone) == startYear
na
else
var sum = 0.
if year(time[1], syminfo.timezone) < year(time, syminfo.timezone)
sum := 0
sum += close
sum
```
### Инпуты в сканерных скриптах не нужны
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@


## Как обновлять код индикаторов
Для обновления скрипта индикатора, отредактируйте соответствующий .pine файл
Для добавления скрипта индикатора, добавьте соответствующий .pine файл
Для начала прочитать [рекомендации](BEST_PRACTICES.md)
Для обновления скрипта индикатора, отредактируйте соответствующий .pine файл
Для добавления скрипта индикатора, добавьте соответствующий .pine файл

После внесенных изменений, запустите утилиту pine_compiler (https://git.xtools.tv/tv/scanner/tree/master/pine_compiler):
```shell
Expand Down
33 changes: 21 additions & 12 deletions links/24h_volume.pine.link
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
// 24h volume
price = close
currency = "USD"
msIn24h = 24*60*60*1000
countOfFiveMinsInDay = 24*60/5
maxBufferSize = 2*countOfFiveMinsInDay
cumVolTF = "5"
cum24hVol(s) =>
src = s
if bar_index==0
src := src[maxBufferSize] * time[maxBufferSize] * 0
expr(offset, maxBufferSize) =>
if (syminfo.volumetype == "quote")
max_bars_back(volume, maxBufferSize)
volume[offset]
else
if syminfo.volumetype == "base"
max_bars_back(close, maxBufferSize)
max_bars_back(volume, maxBufferSize)
close[offset] * volume[offset]
else
na

cum24hVol() =>
max_bars_back(time, maxBufferSize)
var cumSum = 0.
var int firstBarTimeIndex = na
if na(firstBarTimeIndex) // 24 H have not elapsed yet
Expand All @@ -17,20 +26,20 @@ cum24hVol(s) =>
if (time - time[i]) >= msIn24h
firstBarTimeIndex := bar_index - i + 1
break
sum += src[i]
sum += expr(i, maxBufferSize)
cumSum := sum
else
cumSum += nz(src)
cumSum += nz(expr(0, maxBufferSize))
for i = firstBarTimeIndex to bar_index
if (time - time[bar_index - i]) < msIn24h
firstBarTimeIndex := i
break
cumSum -= nz(src[bar_index - i])
cumSum -= nz(expr(bar_index - i, maxBufferSize))
if cumSum <= 0
cumSum := 0
cumSum
expr = syminfo.volumetype == "quote" ? volume : ( syminfo.volumetype == "base" ? price*volume : na )
vol24h = request.security(syminfo.tickerid, cumVolTF, cum24hVol(expr), lookahead = barmerge.lookahead_off, currency = currency, ignore_invalid_symbol=true)

vol24h = request.security(syminfo.tickerid, cumVolTF, cum24hVol(), lookahead = barmerge.lookahead_off, currency = currency, ignore_invalid_symbol=true)
plot(vol24h, title = "24h_vol", style = plot.style_columns)

// volume in base and quote currencies
Expand All @@ -42,8 +51,8 @@ plot(volQuote, title = "volume_quote", style = plot.style_columns)
// 24h prev value (generic)
prev24hVal(source) =>
src = source
if bar_index == 0
src := src[maxBufferSize] * time[maxBufferSize] * 0
max_bars_back(src, maxBufferSize)
max_bars_back(time, maxBufferSize)
int BB24h = na
for i = 0 to countOfFiveMinsInDay
if (time - time[i]) >= msIn24h
Expand Down
Loading

0 comments on commit a5149d5

Please sign in to comment.