Библиотеки Pine Script: импорт, экспорт и версии функций

Обложка статьи «Библиотеки Pine Script: импорт, экспорт и версии функций»: слева блок библиотеки с тремя экспортируемыми функциями, справа три скрипта; два подключены к первой версии, третий переведён на вторую

Когда библиотека оправдана, а когда хватит копипасты?

Честный порог простой. Пока расчёт нужен одному скрипту, он и должен лежать внутри этого скрипта. Как только вы ловите себя на том, что открываете старый индикатор, чтобы скопировать оттуда функцию, а потом ещё раз, и ещё, копипаста начинает стоить дороже, чем разовая возня с публикацией.

Цена у библиотеки есть, и о ней лучше знать заранее. Её нельзя просто сохранить в редакторе и подключить: она обязана быть опубликована, хотя бы приватно. Публикуется она всегда с открытым исходником, другого варианта TradingView не даёт. И править её задним числом уже не выйдет так же свободно, как черновик в редакторе.

Взамен вы получаете одно место правды. Поправили формулу в библиотеке, выпустили новую версию, и дальше решаете сами, какие скрипты на неё переводить. Никто не переведётся втихую, и это не недоработка, а сознательное решение площадки.

Кому библиотека сэкономит время

Подойдёт, если

  • Один и тот же расчёт живёт в трёх и более ваших скриптах
  • Вы пишете набор индикаторов с общей логикой сигналов
  • Хотите отдать свои функции другим авторам
  • Собираете внутренний набор утилит: округление, форматирование, работа с сессиями

Не подойдёт, если

  • Функция нужна ровно одному индикатору
  • Код меняется каждый день и ещё не устоялся
  • Логику нельзя показывать: библиотека всегда открытая
  • Нужен закрытый продукт для продажи доступа

Если вы только присматриваетесь к языку и ещё не решили, стоит ли писать своё, начните с общей картины: что такое Pine Script и как он устроен. Библиотеки это уже вторая ступень, они нужны не всем.

Чем library() отличается от indicator() и strategy()?

Библиотеки Pine Script это третий тип скрипта наравне с индикатором и стратегией. Каждый скрипт начинается ровно с одного объявления, и оно стоит в глобальной области. Значит, выбор простой: либо indicator(), либо strategy(), либо library(). Третьего не дано и совмещения тоже.

Отличий у библиотеки от индикатора несколько, и почти все они логичны.

Слово export доступно только библиотекам. Индикатор при всём желании не может отдать свою функцию другому скрипту, это не запрет ради запрета, а разделение ролей.

Заголовок библиотеки работает как имя пространства имён, и правила к нему строже. Годятся только латинские буквы, цифры и подчёркивание, начинаться с цифры нельзя. Строка "Library for 14-day averages" вызовет ошибку компиляции просто из-за пробелов и дефиса, а "Library_for_14_day_averages" пройдёт.

Библиотеку не предполагается вешать на график. Справка TradingView говорит об этом прямо: библиотеки не для того, чтобы их накладывать, их импортируют, когда пишут другой скрипт. Технически код на графике всё же исполняется как обычный индикатор, и этим пользуются, чтобы подготовить чистый график перед публикацией.

И ещё одна мелочь, которая всплывает позже: сама библиотека не создаёт алерты. Она может экспортировать функцию с вызовом alert() внутри, а алерт уже создаст тот скрипт, который эту функцию вызвал.

Как собрать библиотеку: от функции до export

Каркас библиотеки в шестой версии языка выглядит так:

//@version=6
// @description Короткое описание, что тут лежит
library("My_Tools", overlay = true)

export myEma(int x) =>
    ta.ema(close, length = x)

У объявления library() ровно три параметра: title, overlay и dynamic_requests. Первый обязателен, он же служит идентификатором при импорте. Второй отвечает за то, попадёт ли рисунок на основную панель графика, по умолчанию нет. Третий разрешает динамические запросы, и в шестой версии он по умолчанию включён, тогда как в пятой был выключен.

Экспортировать можно не только функции. В список входят методы, пользовательские типы, enum и константные переменные. Константы приехали в язык позже остальных, в июне 2025 года, и у них своё условие: тип только int, float, bool, color или string, а в объявлении обязательно слово const.

С типами и enum есть неочевидное правило. Если экспортируемая функция принимает или возвращает объект вашего типа, то и сам тип обязан быть экспортирован. То же самое, если поле одного экспортируемого типа использует другой. А вот если тип нужен только для внутренней кухни библиотеки, наружу его выносить не надо.

Пустая библиотека не соберётся. Чтобы компиляция прошла, наружу должно уходить хотя бы одно имя: функция, метод, тип, enum или константная переменная.

  1. 1

    Выделить функцию

    Найти расчёт, который вы копируете из скрипта в скрипт

  2. 2

    Заменить объявление на library

    Заголовок только латиницей, цифрами и подчёркиванием

  3. 3

    Поставить export и типы

    Тип обязателен у каждого параметра, иначе не соберётся

  4. 4

    Убрать входы и глобальные ссылки

    Внутри нельзя вызывать input и брать глобальные массивы

  5. 5

    Проверить на графике

    Код библиотеки исполняется как обычный индикатор

  6. 6

    Опубликовать приватно или публично

    Без публикации импортировать библиотеку невозможно

Порядок действий, если у вас уже есть рабочая функция внутри обычного индикатора и вы хотите переиспользовать её в других скриптах.

Открыть редактор, сохранить черновик и добавить скрипт на график это отдельная механика, она подробно разобрана в статье про редактор Pine Script.

Почему у параметров экспортируемой функции обязательны типы?

Формулировка документации не оставляет свободы: у экспортируемой функции указание типа каждого параметра обязательно. У обычной функции типы чаще можно не писать, но они допустимы, а с аргументом по умолчанию na или явным квалификатором тоже обязательны. У метода тип первого параметра обязателен отдельно. Причина утилитарная. Функция уезжает к чужим людям, и компилятор обязан заранее знать её контракт.

Кроме типа у параметра бывает квалификатор, и тут выбор всего из двух слов: simple и series. Слово const в экспортируемой функции не разрешено, оно доступно только обычным, неэкспортируемым.

По умолчанию аргументы приезжают как series, если вы явно не написали simple. Компилятор при этом смотрит, как параметр используется внутри, и подбирает квалификатор сам. Отсюда самая частая ловушка, которую документация показывает буквально на пальцах. Возьмём функцию:

export myEma(int x) =>
    ta.ema(close, length = x)

Параметр x уходит в аргумент длины, а длина у скользящей средней обязана быть простым значением. Значит, x автоматически получает квалификатор simple. Вызов myEma(x = 20) соберётся спокойно, а вот myEma(x = bar_index) даст ошибку компиляции: bar_index меняется на каждом баре, это серия. Ничего мистического, просто контракт функции оказался жёстче, чем выглядел в коде.

Обратная ситуация тоже бывает. Если вам нужно, чтобы функция вернула простое значение, а не серию, придётся следить, чтобы внутри не оказалось ни одного серийного значения. Достаточно одного, и результат станет серией.

Что нельзя делать внутри экспортируемой функции?

Документация даёт закрытый список ограничений, и его стоит прочитать целиком один раз, чтобы потом не гадать.

Первое. Нельзя обращаться к переменным глобальной области библиотеки, кроме тех, что объявлены как константы. Значение, пришедшее из настроек, или массив, созданный глобально, внутри экспортируемой функции недоступны.

Второе. Нельзя вызывать функции семейства input. Настройки живут в скрипте-потребителе, а не в библиотеке, и это правильно: иначе одна библиотека диктовала бы интерфейс всем, кто её подключил.

Третье. Запросы request.*() внутри локальной области разрешены, пока параметр dynamic_requests не выключен вручную. Но у них своё условие: аргумент expression не может зависеть от параметров вашей функции. Тикер и таймфрейм зависеть могут, а само выражение нет.

Четвёртое. alert() внутри функции разрешён, но алерт создаст только тот, кто эту функцию вызвал. С самой библиотеки, висящей на графике, алерт не сделать.

Пятое. Библиотечная функция всегда возвращает simple или series, слабее не бывает. Поэтому её результат нельзя подставить туда, где ждут константу. Классический пример: параметр show_last у plot() требует значения типа input int или const int, и вернуть его из библиотеки не получится.

К этому добавляются два общих правила языка, про которые часто забывают. Вызов plot() живёт только в глобальной области, то есть внутри любой функции его не бывает вообще. А рекурсия у пользовательских функций запрещена, вызвать саму себя нельзя.

Как опубликовать библиотеку и кто её увидит?

Пока библиотека не опубликована, импортировать её нельзя. Никакого «сохранил в редакторе и подключил» тут не предусмотрено.

Выбор между приватной и публичной публикацией сводится к тому, кого вы зовёте. Приватная не попадает в ленту сообщества и не находится поиском, а виджет виден только в вашем профиле. Но важная деталь, о которой часто пишут неверно: страница приватной публикации открывается по прямой ссылке любому, у кого эта ссылка есть. Это не сейф, это скрытая от поиска витрина.

Правила сочетаемости стоит запомнить один раз. Публичный скрипт с открытым кодом подключает публичные библиотеки. Приватные скрипты и черновики в редакторе могут брать и публичные, и приватные библиотеки. У публичных protected и invite-only скриптов есть отдельное исключение: документация разрешает им использовать приватные библиотеки.

Право на правку у двух вариантов разное. Приватную публикацию автор может менять и удалять всегда. У публичной заголовок и исходное описание можно править, а саму публикацию удалять только первые пятнадцать минут. Код при этом можно обновлять и позже: для этого публикуют новую версию, а изменения описывают в заметке к обновлению. Поэтому в исходное описание публичной библиотеки не пишут ничего, что скоро устареет.

Про чужой код правила площадки говорят предметно: импортированный код публичных библиотек отнесён к общественному достоянию. Для такого импорта отдельное разрешение автора не требуется, даже в закрытой публикации, если импортированный код составляет только часть вашего скрипта. Копирование чужого исходника в свою закрытую публикацию это другой случай: на него нельзя автоматически переносить исключение для import, нужно соблюдать правила повторного использования и получить явное разрешение автора. Автора указывают в описании. Открытый код по умолчанию идёт под лицензией Mozilla Public License 2.0, если автор не написал в исходнике другую.

И про тарифы, раз уж это упирается в деньги. На тарифе Basic публичных публикаций нет вовсе, приватные доступны. Для публичных действуют лимиты частоты: до пяти за скользящие сутки и до пятнадцати за тридцать дней. На приватные публикации и на обновления уже опубликованных скриптов эти лимиты не распространяются.

Как импортировать библиотеку и зачем нужен alias?

Синтаксис такой:

//@version=6
indicator("Using AllTimeHighLow library", "", true)
import PineCoders/AllTimeHighLow/1 as allTime

plot(allTime.hi())
plot(allTime.lo())

Путь из трёх частей однозначно определяет, что именно вы подключили. Здесь есть подвох, на который натыкаются регулярно: в импорте пишется title из объявления библиотеки, а не заголовок, который автор придумал для публикации. Это часто разные строки.

Псевдоним после as задаёт пространство имён. С as allTime функции зовут как allTime.hi(). Если псевдоним не писать, пространством имён станет само имя библиотеки. Через ту же точечную запись доступны и типы, и enum библиотеки.

Несколько правил про импорт, которые проще запомнить сразу:

  • Номер версии в пути пишется явно всегда, значения «последняя» в этой строке не существует.
  • Публичный скрипт с открытым кодом подключает публичные библиотеки.
  • Приватная библиотека годится для личного скрипта, черновика в редакторе и для публичного скрипта с закрытым кодом.

Число подключённых библиотек напрямую не ограничено, ограничен суммарный объём кода. Об этом ниже, в рисках.

  1. 1

    Открыть страницу библиотеки

    Публичные библиотеки лежат в ленте Community scripts

  2. 2

    Скопировать строку импорта

    На странице есть кнопка копирования готовой строки

  3. 3

    Вставить import под объявлением

    Номер версии в строке останется тем, что вы взяли

  4. 4

    Задать понятный псевдоним

    После as пишут короткое имя, через него зовут функции

  5. 5

    Указать автора в описании

    Требование правил площадки, а не вежливость

Короткий путь, если вы нашли в ленте сообщества готовую библиотеку Pine Script и хотите вызвать её функцию у себя.

Библиотека помогает переиспользовать расчёт, но сама не превращает его в проверенную торговую систему. Если ваша задача сейчас читать график, а не поддерживать собственный код, у Midas есть готовый индикатор для TradingView. Это отдельный путь: исходники библиотеки он вам не выдаёт и правильность вашей функции не подтверждает.

Почему импорт не переезжает на новую версию сам?

Формулировка документации прямая: чтобы скрипты, использующие библиотеки, работали надёжно, автоматически подхватить последнюю версию невозможно. Каждый раз, когда автор публикует обновление, номер версии библиотеки растёт. Хотите новую версию, идите и меняйте число в строке import.

Звучит как неудобство, а на деле это страховка. Представьте обратное: автор чужой библиотеки поправил формулу у себя, и наутро ваш индикатор рисует другие сигналы, хотя вы к нему не прикасались. Именно этого площадка и не допускает.

Практический вывод: смена номера версии это изменение поведения вашего скрипта, а не косметика. После неё сигналы стоит пересмотреть заново: прогнать бэктест на том же инструменте и проверить индикатор на перерисовку, ровно как вы делаете это с любой правкой логики. Совпадение старого и нового результата никто не гарантирует.

Где взять актуальный номер. На странице опубликованной библиотеки есть кнопка копирования готовой строки импорта в буфер обмена, это самый быстрый способ. Второй вариант, для тех, кто пишет вручную: в редакторе работает автодополнение по имени автора, оно покажет доступные библиотеки.

Как выпускать версии, чтобы не сломать чужие скрипты?

Библиотеки Pine Script нумеруются механически: площадка про смысл номера ничего не говорит и просто увеличивает его при каждой публикации обновления. Значит, дисциплину придётся держать самому, и тут проще одолжить готовую у соседних экосистем.

Спецификация Semantic Versioning формулирует правило, ради которого её и стоит открыть: выпущенная версия не меняется, любое изменение выходит новым выпуском. На TradingView это работает буквально, потому что публикация создаёт независимую копию исходника и она становится частью истории версий.

Что считать ломающим изменением, удобно смотреть по разбору из документации Cargo: удаление публичного элемента ломает совместимость, добавление обязательного параметра функции тоже, а вот добавление нового публичного элемента совместимо. Переводится на Pine Script один в один. Дописали в библиотеку новую экспортируемую функцию, старые потребители ничего не заметили. Добавили обязательный аргумент в существующую, и все, кто вызывал её по-старому, приехали.

Документация npm даёт совсем простую памятку по числам: первый выпуск 1.0.0, исправление 1.0.1, совместимая новинка 1.1.0, ломающее изменение 2.0.0. Правда, честнее сразу оговориться, как это делает руководство по упаковке Python: строгий semver на практике соблюдают не все, и номер в конце концов остаётся суждением автора.

Отдельно про описание. Раз публичную публикацию нельзя править после пятнадцати минут, историю изменений имеет смысл вести дисциплинированно с самого начала. Подход Keep a Changelog тут кстати: список изменений пишется для людей, у каждой версии своя запись с датой и понятными пунктами. Иначе через год вы сами не вспомните, чем третья версия отличалась от второй.

Ничего не ломается

Ломается у всех

  1. 1.Добавили новую функцию
  2. 2.Изменили расчёт внутри функции
  3. 3.Убрали или переименовали экспорт
Ориентир, когда достаточно тихо выпустить обновление, а когда стоит предупредить тех, кто вашу библиотеку уже импортировал.

Как перейти на новую версию и не потерять рабочую?

Сначала сохраните копию скрипта-потребителя с прежним импортом. Потом меняйте номер версии в копии, а не сразу во всех индикаторах. Новая версия может собраться без ошибки и при этом считать иначе: компилятор проверяет типы, а не то, совпал ли ваш торговый смысл.

Для сравнения оставьте тот же инструмент, таймфрейм и настройки. Посмотрите участок истории, где функция действительно используется: значения линии, места меток, поведение на первых барах. Если новая версия добавляет обязательный параметр, поправьте каждый вызов, включая вызовы внутри ваших вспомогательных функций. Если изменились возвращаемые значения, проверьте код, который их разбирает.

Нашли расхождение, которого не ожидали, верните прежнее число в import в тестовой копии и разберитесь с изменениями автора. Перевод остальных скриптов отложите. В описании своего обновления запишите, какую версию библиотеки взяли и что поменялось для пользователя. Такая запись потом полезнее, чем «обновили зависимости».

Что изменилось в библиотеках с выходом Pine Script v6?

До шестой версии запрос данных внутри экспортируемой функции был закрыт, если автор не включал динамические запросы вручную. В ноябре 2024 года вместе с выходом v6 это изменилось: вызовы request.*() разрешили внутри циклов, условных конструкций и экспортируемых функций библиотек.

Заодно поменялось умолчание. В пятой версии dynamic_requests был выключен, в шестой включён. При переносе старого кода из-за этого попадаются в ловушку: если в объявлении остался явный dynamic_requests = false, то вызов запроса из локальной области будет запрещён, даже когда он спрятан внутри пользовательской функции. Руководство по миграции советует простое лечение: при конвертации просто убрать явный параметр и дать компилятору решить самому.

  1. Октябрь 2021

    Библиотеки появились в Pine Script v5

    Новый тип публикации для переиспользуемых функций

  2. Июнь 2024

    В язык добавили enum-типы

    Новый тип данных со списком допустимых значений

  3. Ноябрь 2024

    Pine Script v6 и динамические запросы

    request разрешён внутри экспортируемых функций

  4. Июнь 2025

    Экспорт константных переменных

    Только int, float, bool, color и string со словом const

Четыре момента, которые определяют, что именно ваша библиотека умеет сегодня и какой синтаксис вы встретите в чужом коде.

Если вы собираете из своих функций не просто набор утилит, а рабочий алгоритм, дальше пригодится общая рамка проверки: как устроен алготрейдинг и чем проверяют алгоритм до того, как доверить ему решения.

Риски и ограничения

Про объём. Скомпилированная форма одного скрипта ограничена примерно ста тысячами токенов, точное число 100 256. Библиотеки компилируются отдельно, и их код не раздувает размер вашего индикатора. Зато суммарный объём всех подключённых библиотек ограничен миллионом токенов, а сам запрос на компиляцию не может превышать пять мегабайт.

Тут важно не смешивать два лимита. На компиляцию отправляется библиотека целиком, даже если вы вызвали одну функцию. Это раздувает запрос с исходниками, у которого потолок пять мегабайт. Но после компиляции неиспользуемый код, не влияющий на вывод скрипта, компилятор отбрасывает. Поэтому размер отправленного исходника и число токенов в готовой форме это разные вещи. Вывод простой: библиотеки лучше держать компактными и по темам, а не сваливать всё в одну. Для ошибки размера запроса убирайте ненужные импорты; для ошибки токенов смотрите используемую логику, длинные строки и повторяющиеся расчёты.

Ещё одна мелочь из той же оперы: запросы request.*() внутри импортированных функций считаются в ваш лимит запросов, даже если точно такой же запрос с теми же аргументами уже есть в основном коде скрипта.

Про зависимость. Подключая чужую библиотеку, вы принимаете чужие решения о расчётах. Автор выпустит новую версию, вы её не увидите, пока сами не переключитесь, и это хорошо. Но и обратное верно: если в старой версии есть ошибка, она останется у вас, пока вы не обновитесь вручную.

Про приватность. Повторим то, о чём говорили выше, потому что на этом обжигаются: приватная публикация скрыта от ленты и поиска, но открывается по прямой ссылке. Код, который нельзя показывать никому, в библиотеку не выносят вовсе.

Про авторство. Указать автора чужой библиотеки в описании своей публикации это не вежливость, а требование правил площадки. За плагиат правила площадки предусматривают вплоть до постоянной блокировки аккаунта, так что кредит автору это ещё и страховка.

И честная оговорка про эту статью. Точных текстов ошибок компиляции для случаев вроде пропущенного типа параметра или вызова input внутри экспортируемой функции в официальной документации нет: там описаны сами запреты. Так что если компилятор вам что-то выдал, сверяйтесь со списком ограничений, а не с чужими пересказами.

Источники

Частые вопросы

Обязательно ли публиковать библиотеку, чтобы ей пользоваться?

Да. Пока библиотека не опубликована, импортировать её нельзя. Приватной публикации при этом достаточно, в ленту сообщества она не попадёт.

Можно ли скрыть исходный код библиотеки?

Нет. Все библиотеки публикуются только с открытым исходником, выбрать другой тип видимости нельзя. Приватная публикация скрывает её от поиска, но не от того, у кого есть ссылка.

Почему в экспортируемой функции нельзя использовать input?

Настройки принадлежат скрипту-потребителю. Экспортируемая функция не может вызывать функции семейства input и не может брать глобальные переменные, инициализированные из настроек.

Обновится ли мой скрипт сам, когда автор выпустит новую версию библиотеки?

Нет. Номер версии в строке импорта закреплён, автоматического перехода на последнюю версию не существует. Переключение это ручная правка числа.

Можно ли подключить несколько библиотек в один скрипт?

Да, число импортов напрямую не ограничено. Ограничен суммарный объём: все подключённые библиотеки вместе не должны превышать миллион токенов. При этом каждый импорт пишется отдельной строкой со своим номером версии, а обращаться к функциям удобнее через понятный псевдоним после as.

Можно ли пользоваться чужой библиотекой из ленты TradingView?

Да, библиотеки отнесены правилами площадки к общественному достоянию: вызывать их функции и переиспользовать код в открытом скрипте разрешено без запроса автору. Для import публичной библиотеки в закрытую публикацию в действующих Script Publishing Rules есть исключение, если импортированный код составляет только часть скрипта. Копирование чужого исходника в закрытую публикацию требует отдельного разбора и явного разрешения автора. Автора указывают в описании в любом случае.

График TradingView с сигналами Buy и Sell индикатора Midas
Midas multi-индикатор for TradingViewОдин из самых продвинутых индикаторов для трейдинга
  • Сигналы без перерисовки
  • Интерактивный теханализ
  • 7 стратегий на выбор
Midas multi-индикатор for TradingViewСигнал, стоп и 3 цели - прямо на графике
  • Сигнал фиксируется по закрытию свечи
  • Стоп и 3 цели строятся автоматически
  • План сделки виден до входа