Рабочая среда для системной торговли
Возьмите свою стратегию.
Проверьте её на практике.
Разрабатывайте торговые идеи. Проверяйте их поведение.
Одна рабочая среда для вас и вашего ИИ.
РЫНОЧНЫЕ ДАННЫЕ
Данные 20 бирж и 3 DEX
Спот и фьючерсы, линейные и инверсные контракты — проверяйте стратегии на исторических рыночных данных.
Доступные рынки и глубина истории зависят от площадки и инструмента. Поддержка исторических данных не означает интеграцию реальной торговли.
01 / Возьмите свою стратегию
Начните с того,
что у вас уже есть.
Откройте файл, папку или Git-репозиторий. Разберите различия платформ при переносе с помощью ИИ — или начните в редакторе.Основа — C#; мосты других языков экспериментальны. Успешная компиляция не доказывает эквивалентность торговли.
Справочный пример Range Breakout · отдельная локальная модель. Основная стратегия Multi-Regime — в окне выше.
Выберите файл в проводнике. Изучите правила, измените параметр или проверьте предложенный перенос до его применения.
02 / Разберитесь в результате
Бэктест —
это начало.
Не ограничивайтесь итоговой доходностью. Изучите сделки, капитал и просадку. Проверьте влияние размера риска перед следующим экспериментом.Ниже: Range Breakout на сгенерированных свечах. Реальные вычисления в браузере, без исторических рыночных данных и движка XTester.
Справочный пример Range Breakout · отдельная локальная модель. Основная стратегия Multi-Regime — в окне выше.
Запустите синтетический пример с панели инструментов. Переключитесь с капитала на просадку, изучите сделку или измените риск и повторите расчёт.
03 / Работайте со своим ИИ
Рабочая среда.
Не просто окно чата.
Подключите Claude Code, Codex или другой MCP-клиент к открытому проекту Studio. Держите изменения, исследования и решения перед глазами.Для Studio MCP приложение должно работать. Чувствительные действия требуют согласия. Здесь взаимодействие показано локально, без подключения к агенту.
Справочный пример Range Breakout · отдельная локальная модель. Основная стратегия Multi-Regime — в окне выше.
Выберите запрос в чате, изучите приложенный контекст или настройте клиент в параметрах рабочей среды.
MCP / Claude Code · Codex · Claude Desktop · Cursor
Подключение ИИ-агентов / MCP
Выберите клиент: предполагаемый путь после установки уже подставлен. Проверьте папку и при необходимости измените путь перед подключением.
Ваш следующий эксперимент
Одна рабочая среда.
Более понятная стратегия.
Текущая версия: 1.0.0-alpha.4 · Windows · macOS · Linux
Шаблоны и примеры стратегий
10 языков · ядро C# · экспериментальные мосты · подмножество Pine. Исходники для Studio, не десять браузерных движков.
main.cs
Основной движокСкачатьИсходный каркас жизненного цикла Studio: добавьте торговые решения в обработчик свечи. В этом стартовом файле ордеров нет. Источник
public class UserStrategy : IStrategy
{
// Services available to the strategy: orders, indicators, parameters,
// market data, and logging.
private IApi _api = null!;
private IIndicators _indicators = null!;
private IStrategyParams _params = null!;
private IMarketData _marketData = null!;
private ILogger _logger = null!;
public void OnInit(StrategyContext context)
{
_api = context.Api;
_indicators = context.Indicators;
_params = context.Parameters;
_marketData = context.MarketData;
_logger = context.Logger;
_logger.Info("UserStrategy initialized.");
}
public void OnTick(decimal? price = null)
{
}
// Called for every closed bar in every subscription.
// symbolKey identifies the exchange, market, pair, and timeframe.
public void OnBar(ISymbolKey symbolKey, IKline kline)
{
}
// Called exactly once when a Tester, Paper, or Live run finishes.
public void OnFinish(StrategyFinishContext context)
{
}
}main.py
Экспериментальный SDK-мостСкачатьИсходный каркас жизненного цикла Studio: добавьте торговые решения в обработчик свечи. В этом стартовом файле ордеров нет. Источник
# Add your decisions in on_bar. self.context.api places orders (buy, sell, place_order,
# close_position); self.context.indicators reads the engine's indicators (rsi, sma, ema,
# macd, call("ADX", period=14)); self.context.logger writes to the strategy log.
from xtester import Strategy, OrderSide, OrderType
class UserStrategy(Strategy):
# symbol_key: exchange, market, symbol, timeframe of the closed bar.
# bar: open_time, close_time, open, high, low, close, volume as Decimal.
def on_init(self, context):
context.logger.info("UserStrategy initialized.")
def on_tick(self, price):
pass
def on_bar(self, symbol_key, bar):
pass
def on_finish(self, context):
pass
def create_strategy():
return UserStrategy()main.mjs
Экспериментальный SDK-мостСкачатьУчебный пример для тестера: рыночная покупка на растущей свече и одна попытка закрытия на следующей падающей. Один инструмент, без начальной позиции; принятие заявки не означает исполнение. Не для реальной торговли. Источник
// EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
// First bullish candle: attempt a 0.01 market buy. First later bearish candle:
// attempt to close the whole position. At most one entry and one exit request.
// Acceptance is not a fill; errors stop the example. No retries, restart recovery,
// position reconciliation or risk controls. Choose valid size/funds in Studio.
// GETTING STARTED
// 1. Open Data and download candles for an exchange, market, and symbol.
// 2. Press F5: the XTester engine runs this strategy over the project's candles and
// executes orders, fees and balances itself; this file only decides.
// 3. Add your decisions in onBar. this.context.api places orders (buy, sell, placeOrder,
// closePosition); this.context.indicators reads the engine's indicators (rsi, sma, ema,
// macd, call('ADX', { period: 14 })); this.context.logger writes to the strategy log.
// Ask the AI assistant to explain this file.
import { Strategy, OrderSide, OrderType } from 'xtester';
export class UserStrategy extends Strategy {
phase = 0;
// symbolKey: exchange, market, symbol, timeframe of the closed bar.
// bar: openTime, closeTime, open, high, low, close, volume as numbers (bar.text.* keeps the exact decimals).
onInit(context) {
context.logger.info('UserStrategy initialized.');
}
onTick(price) {
}
onBar(symbolKey, bar) {
if (this.phase === 0 && bar.close > bar.open) {
const result = this.context.api.buy('0.01');
this.phase = result.success ? 1 : 2;
if (!result.success) this.context.logger.info(result.errorMessage);
} else if (this.phase === 1 && bar.close < bar.open) {
const result = this.context.api.closePosition();
this.phase = 2;
if (!result.success) this.context.logger.info(result.errorMessage);
}
}
onFinish(context) {
}
}
export function createStrategy() {
return new UserStrategy();
}
main.ts
Экспериментальный SDK-мостСкачатьИсходный каркас жизненного цикла Studio: добавьте торговые решения в обработчик свечи. В этом стартовом файле ордеров нет. Источник
// The XTester engine type-checks this strategy, runs it over the project's candles
// and executes orders, fees and balances itself; this file only decides.
import { Strategy, OrderSide, OrderType, type Bar, type Context, type SymbolKey } from 'xtester';
export class UserStrategy extends Strategy {
// symbolKey: exchange, market, symbol, timeframe of the closed bar.
// bar: openTime, closeTime, open, high, low, close, volume as numbers.
onInit(context: Context): void {
context.logger.info('UserStrategy initialized.');
}
onTick(price: number | undefined): void {
}
onBar(symbolKey: SymbolKey, bar: Bar): void {
}
onFinish(context: Context): void {
}
}
export function createStrategy(): UserStrategy {
return new UserStrategy();
}main.java
Экспериментальный SDK-мостСкачатьУчебный пример для тестера: рыночная покупка на растущей свече и одна попытка закрытия на следующей падающей. Один инструмент, без начальной позиции; принятие заявки не означает исполнение. Не для реальной торговли. Источник
// EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
// First bullish candle: attempt a 0.01 market buy. First later bearish candle:
// attempt to close the whole position. At most one entry and one exit request.
// Acceptance is not a fill; errors stop the example. No retries, restart recovery,
// position reconciliation or risk controls. Choose valid size/funds in Studio.
// GETTING STARTED
// 1. Open Data and download candles for an exchange, market, and symbol.
// 2. Press F5: the XTester engine runs this strategy over the project's candles and
// executes orders, fees and balances itself; this file only decides. A JDK is needed:
// Studio offers the Java language pack when none is installed.
// 3. Add your decisions in onBar. context.api() places orders (buy, sell, placeOrder,
// closePosition); context.indicators() reads the engine's indicators (rsi, sma, ema,
// macd, call("ADX", "period", 14)); context.logger() writes to the strategy log.
// Ask the AI assistant to explain this file.
import xtester.Bar;
import xtester.Context;
import xtester.Strategy;
import xtester.SymbolKey;
import java.math.BigDecimal;
class UserStrategy extends Strategy {
private int phase = 0;
@Override
public void onInit(Context context) {
context.logger().info("UserStrategy initialized: " + context.parameters().symbolKey());
}
@Override
public void onTick(BigDecimal price) {
}
@Override
public void onBar(SymbolKey symbolKey, Bar bar) {
if (phase == 0 && bar.close().compareTo(bar.open()) > 0) {
var result = context.api().buy("0.01");
phase = result.success() ? 1 : 2;
if (!result.success()) context.logger().info(result.errorMessage());
} else if (phase == 1 && bar.close().compareTo(bar.open()) < 0) {
var result = context.api().closePosition();
phase = 2;
if (!result.success()) context.logger().info(result.errorMessage());
}
}
@Override
public void onFinish(Context context) {
}
}
main.cpp
Экспериментальный SDK-мостСкачатьУчебный пример для тестера: рыночная покупка на растущей свече и одна попытка закрытия на следующей падающей. Один инструмент, без начальной позиции; принятие заявки не означает исполнение. Не для реальной торговли. Источник
// EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
// First bullish candle: attempt a 0.01 market buy. First later bearish candle:
// attempt to close the whole position. At most one entry and one exit request.
// Acceptance is not a fill; errors stop the example. No retries, restart recovery,
// position reconciliation or risk controls. Choose valid size/funds in Studio.
// GETTING STARTED
// 1. Open Data and download candles for an exchange, market, and symbol.
// 2. Press F5 inside a project: the XTester engine compiles every .cpp of this folder with the
// header-only xtester.hpp and runs it over the project's candles, executing orders, fees and
// balances itself; this file only decides. A C++ compiler is needed (Xcode CLT, clang/g++).
// 3. Add your decisions in onBar. ctx.api places orders (buy, sell, placeOrder, closePosition);
// ctx.indicators reads the engine's indicators (rsi, sma, ema, call("ADX", ...)); ctx.logger
// writes to the strategy log. XTESTER_STRATEGY defines main: never write main yourself.
// Ask the AI assistant to explain this file.
#include "xtester.hpp"
class UserStrategy : public xtester::Strategy {
int phase = 0;
void onInit(xtester::Context& ctx) override {
ctx.logger.info("UserStrategy initialized: " + ctx.parameters.symbolKey.str());
}
void onTick(xtester::Context& ctx, std::optional<double> price) override {
}
void onBar(xtester::Context& ctx, const xtester::SymbolKey& symbolKey, const xtester::Bar& bar) override {
if (phase == 0 && bar.close > bar.open) {
auto result = ctx.api.buy("0.01");
phase = result.success ? 1 : 2;
if (!result.success) ctx.logger.info(result.errorMessage);
} else if (phase == 1 && bar.close < bar.open) {
auto result = ctx.api.closePosition();
phase = 2;
if (!result.success) ctx.logger.info(result.errorMessage);
}
}
void onFinish(xtester::Context& ctx) override {
}
};
XTESTER_STRATEGY(UserStrategy)
main.rs
Экспериментальный SDK-мостСкачатьУчебный пример для тестера: рыночная покупка на растущей свече и одна попытка закрытия на следующей падающей. Один инструмент, без начальной позиции; принятие заявки не означает исполнение. Не для реальной торговли. Источник
// EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
// First bullish candle: attempt a 0.01 market buy. First later bearish candle:
// attempt to close the whole position. At most one entry and one exit request.
// Acceptance is not a fill; errors stop the example. No retries, restart recovery,
// position reconciliation or risk controls. Choose valid size/funds in Studio.
// GETTING STARTED
// 1. Open Data and download candles for an exchange, market, and symbol.
// 2. Press F5 inside a project: the XTester engine builds this folder as a crate around the
// xtester SDK and runs it over the project's candles, executing orders, fees and balances
// itself; this file only decides. A Rust toolchain is needed: Studio offers the Rust language pack.
// 3. Add your decisions in on_bar. ctx.api places orders (buy, sell, place_order, close_position);
// ctx.indicators reads the engine's indicators (rsi, sma, ema, call("ADX", ...)); ctx.logger
// writes to the strategy log (println! breaks the protocol). The engine generates main.
// Ask the AI assistant to explain this file.
use xtester::*;
#[derive(Default)]
struct UserStrategy { phase: u8 }
impl Strategy for UserStrategy {
fn on_init(&mut self, ctx: &Context) {
ctx.logger.info(format!("UserStrategy initialized: {}", ctx.parameters.symbol_key));
}
fn on_tick(&mut self, ctx: &Context, price: Option<f64>) {
}
fn on_bar(&mut self, ctx: &Context, symbol_key: &SymbolKey, bar: &Bar) {
if self.phase == 0 && bar.close > bar.open {
let result = ctx.api.buy("0.01");
self.phase = if result.success { 1 } else { 2 };
if !result.success { ctx.logger.info(result.error_message); }
} else if self.phase == 1 && bar.close < bar.open {
let result = ctx.api.close_position(None, None);
self.phase = 2;
if !result.success { ctx.logger.info(result.error_message); }
}
}
fn on_finish(&mut self, ctx: &Context) {
}
}
pub fn create_strategy() -> Box<dyn Strategy> {
Box::new(UserStrategy::default())
}
main.go
Экспериментальный SDK-мостСкачатьУчебный пример для тестера: рыночная покупка на растущей свече и одна попытка закрытия на следующей падающей. Один инструмент, без начальной позиции; принятие заявки не означает исполнение. Не для реальной торговли. Источник
// EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
// First bullish candle: attempt a 0.01 market buy. First later bearish candle:
// attempt to close the whole position. At most one entry and one exit request.
// Acceptance is not a fill; errors stop the example. No retries, restart recovery,
// position reconciliation or risk controls. Choose valid size/funds in Studio.
// GETTING STARTED
// 1. Open Data and download candles for an exchange, market, and symbol.
// 2. Press F5 inside a project: the XTester engine builds this folder (package main) with the
// xtester SDK and runs it over the project's candles, executing orders, fees and balances
// itself; this file only decides. A Go toolchain is needed: Studio offers the Go language pack.
// 3. Add your decisions in OnBar. ctx.Api places orders (Buy, Sell, PlaceOrder, ClosePosition);
// ctx.Indicators reads the engine's indicators (RSI, SMA, EMA, Call("ADX", ...)); ctx.Logger
// writes to the strategy log. Do not write func main: the engine generates it.
// Ask the AI assistant to explain this file.
package main
import (
"fmt"
"xtester"
)
type UserStrategy struct {
xtester.Base
phase int
}
func init() { xtester.Register(func() xtester.Strategy { return &UserStrategy{} }) }
func (s *UserStrategy) OnInit(ctx *xtester.Context) {
ctx.Logger.Info(fmt.Sprintf("UserStrategy initialized: %s", ctx.Parameters.SymbolKey))
}
func (s *UserStrategy) OnTick(ctx *xtester.Context, price *float64) {
}
func (s *UserStrategy) OnBar(ctx *xtester.Context, symbolKey xtester.SymbolKey, bar xtester.Bar) {
if s.phase == 0 && bar.Close > bar.Open {
result := ctx.Api.Buy("0.01")
if result.Success { s.phase = 1 } else { s.phase = 2; ctx.Logger.Info(result.ErrorMessage) }
} else if s.phase == 1 && bar.Close < bar.Open {
result := ctx.Api.ClosePosition(nil, "")
s.phase = 2
if !result.Success { ctx.Logger.Info(result.ErrorMessage) }
}
}
func (s *UserStrategy) OnFinish(ctx *xtester.Context) {
}
main.r
Экспериментальный SDK-мостСкачатьУчебный пример для тестера: рыночная покупка на растущей свече и одна попытка закрытия на следующей падающей. Один инструмент, без начальной позиции; принятие заявки не означает исполнение. Не для реальной торговли. Источник
# EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
# First bullish candle: attempt a 0.01 market buy. First later bearish candle:
# attempt to close the whole position. At most one entry and one exit request.
# Acceptance is not a fill; errors stop the example. No retries, restart recovery,
# position reconciliation or risk controls. Choose valid size/funds in Studio.
# GETTING STARTED
# 1. Open Data and download candles for an exchange, market, and symbol.
# 2. Press F5 inside a project: the XTester engine runs this file with Rscript over the
# project's candles, executing orders, fees and balances itself; this file only decides.
# R must be installed (https://cloud.r-project.org); the R pack adds jsonlite and the language server.
# 3. Add your decisions in on_bar. context$api places orders (buy, sell, place_order,
# close_position); context$indicators reads the engine's indicators (rsi, sma, ema,
# call("ADX", list(period = 14))); context$logger writes to the strategy log.
# Ask the AI assistant to explain this file.
create_strategy <- function() {
state <- new.env()
state$phase <- 0L
list(
on_init = function(context) {
context$logger$info(paste("UserStrategy initialized:", xtester_symbol_text(context$parameters$symbol_key)))
},
on_tick = function(context, price) {
},
on_bar = function(context, symbol_key, bar) {
if (state$phase == 0L && bar$close > bar$open) {
result <- context$api$buy("0.01")
state$phase <- if (result$success) 1L else 2L
if (!result$success) context$logger$info(result$error_message)
} else if (state$phase == 1L && bar$close < bar$open) {
result <- context$api$close_position()
state$phase <- 2L
if (!result$success) context$logger$info(result$error_message)
}
},
on_finish = function(context) {
}
)
}
main.pine
Интерпретатор подмножества PineСкачатьИсходная стратегия пересечения EMA для интерпретатора подмножества Pine. Источник
//@version=6
// XTester's own Pine interpreter runs this script once per closed bar and
// the engine executes strategy.entry / strategy.exit / strategy.close orders,
// fees and balances. Plots and drawings are accepted and ignored.
strategy("UserStrategy", overlay = true, default_qty_type = strategy.percent_of_equity, default_qty_value = 10)
fast = ta.ema(close, input.int(9, "Fast EMA"))
slow = ta.ema(close, input.int(21, "Slow EMA"))
if ta.crossover(fast, slow)
strategy.entry("Long", strategy.long)
if ta.crossunder(fast, slow)
strategy.close("Long")
plot(fast, "Fast", color.new(color.blue, 0))
plot(slow, "Slow", color.new(color.orange, 0))Экосистема
Исследуйте здесь. Публикация — отдельный путь.
CopyTrader — отдельный продукт. Доступность публикации и коммерческие условия требуют подтверждения. Это демо не торгует и не монетизирует стратегии.
Об отдельном продукте ↗Вопросы и ответы
Нужно ли уметь программировать?
Необязательно. Опишите идею словами: мастер ТЗ поможет сформулировать правила, а ИИ-помощник — написать и поправить код. Для ИИ-функций нужен подключённый провайдер — ваш ключ или локальная модель. Если пишете сами, в редакторе есть шаблоны, подсказки и диагностика.
На каком языке пишутся стратегии?
На C#, Python, JavaScript, TypeScript, Pine Script, Java, C++, Rust, Go или R. C# — основной язык с наиболее полной поддержкой разработки, исполнения и AI Lab. Для остальных языков есть адаптеры запуска и бэктеста. API, библиотеки и результаты на разных языках могут отличаться.
Можно ли перенести существующую стратегию?
Да. Мастер конвертации принимает файл, папку, архив, текст, HTTPS-ссылку или GitHub-репозиторий, разбирает логику, задаёт вопросы по несовместимым возможностям, генерирует проект, исправляет ошибки компиляции и выдаёт отчёт о том, что перенесено напрямую, что изменено и что не перенесено. Порт создаётся в новом проекте; для работы мастера нужна ИИ-модель. Результат обязательно проверяйте: сверка с эталонным списком сделок сравнивает время и направление входов и выходов, но не доказывает одинаковых торговых результатов.
Насколько Pine Script совместим с TradingView?
XTester исполняет Pine Script v5/v6 собственным интерпретатором — это не движок TradingView. Поддерживаются ta.*, math.*, str.*, array.*, map.*, input.* и ордера strategy.entry / order / exit / close / cancel. Графики, рисунки и алерты принимаются, но игнорируются; импорт библиотек, matrix.*, enum и часть функций request.* не поддерживаются. Исполнение, комиссии и проскальзывание считает движок XTester, поэтому результаты могут отличаться от TradingView.
Что нужно дополнительно установить для выбранного языка?
Для C#, JavaScript, TypeScript и Pine Script — ничего: компилятор C# встроен в Studio, остальные работают на Node.js, который поставляется вместе со Studio. Для Python, Java, Go и Rust Studio предлагает скачать языковой пакет; для Python подойдёт и ваш интерпретатор. Для C++ нужен компилятор системы (Xcode Command Line Tools, clang/g++ или MinGW-w64) — языковой сервер Studio скачает сам. Для R нужна установленная R; языковой пакет добавит jsonlite и языковой сервер.
Чем обычный бэктест отличается от проверки устойчивости?
Бэктест — прогон стратегии на выбранном периоде и условиях. Проверка устойчивости — отдельный шаг после него: сохранённый результат становится базой, а стратегия прогоняется повторно с изменёнными комиссиями и проскальзыванием и на отдельных рыночных фазах. Итог сохраняется в отчёт вместе с ограничениями проверки. Эпизоды фаз берутся из той же истории, поэтому это не независимая проверка на новых данных, а критерии оценки — настраиваемые ориентиры, а не гарантия.
Можно ли подключить внешнего ИИ-агента?
Да, через MCP: совместимый клиент работает с проектом, данными, тестами и результатами. Каждое внешнее подключение подтверждается в окне Studio, доступ можно дать только на чтение, а вносить изменения одновременно может только одна сессия. Подробнее о MCP
Что работает локально, а что требует сети?
Локально работают редактор, проекты, скачанная история, симуляция, бэктест и отчёты; вход в аккаунт и ключи бирж для этого не нужны. Сеть нужна для загрузки истории и списков инструментов с бирж, ИИ-функций с облачным провайдером, скачивания языковых пакетов, обновлений и работы с GitHub. Локальное хранение проекта не означает, что все сетевые функции работают автономно; без облака можно обойтись, если подключить локальную модель ИИ.
Какие биржи поддерживаются?
20 централизованных: Binance, Bybit, OKX, Bitget, KuCoin, MEXC, Gate.io, BingX, HTX, CoinEx, Kraken, Coinbase, Bitfinex, Crypto.com, Deepcoin, XT, BloFin, Bitstamp, CoinW, WEEX — и 3 бессрочных DEX: HyperLiquid, dYdX, Aster. Спот и фьючерсы, линейные и инверсные контракты.
Можно ли из XTester торговать вживую?
Да, через XTester Launcher — приложение для длительного исполнения стратегий, которое входит в пакет Studio. Готовая стратегия запускается из Studio в Launcher: одна стратегия — одно окно. Режимы — Paper (торговля на виртуальном счёте) и Live (через API-ключи вашего счёта на бирже); перед стартом Live Launcher проходит цепочку проверок. В окне видны позиции, ордера и сделки, приходят уведомления, в том числе в Telegram, а если кто-то вмешается в торговлю робота — Launcher предупредит. Торговые решения и риски остаются за вами.
Где хранятся мои данные?
На вашем диске. Телеметрия опциональна и включается только с вашего согласия. При работе с ИИ используется ваш ключ выбранного провайдера или локальная модель; данные, отправленные ИИ-провайдеру, обрабатываются по его правилам.
Сколько стоит?
XTester Studio бесплатен, ограничений по функциональности нет. Внешние ИИ-провайдеры работают по своим условиям и тарифам: запросы с вашим ключом оплачиваются у провайдера. Можно подключить и локальную модель.
Какие нужны требования?
Windows, macOS или Linux (64-bit). Размер, подпись, состав пакета и требования для каждой платформы указаны на странице загрузки по реальным файлам релиза. Для части языков понадобится языковой пакет или инструментарий — см. вопрос выше.
Последние публикации
Загрузка публикаций…