Skip to content

Commit

Permalink
HBS-4254: add BEST_PRACTICES and upd readme
Browse files Browse the repository at this point in the history
  • Loading branch information
stimofeev-tv committed Feb 15, 2024
1 parent 2239911 commit 6cebf76
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 2 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

0 comments on commit 6cebf76

Please sign in to comment.