# Deepwick Script

Deepwick Script 是 Deepwick 图表和回测所用的语言。它是 Pine Script v5/v6 的
**一个子集**：`ta.*`、`math.*`、`str.*`、`array.*`、`map.*`、`input.*`、`plot*` 和 `strategy.*`
的多数调用都与 Pine 中完全一致。Deepwick 与 TradingView 无隶属关系；Pine Script 是
TradingView, Inc. 的商标。

脚本按 K 线逐根运行，从最老的一根到最新的一根，每个变量都保留自己的历史——与 Pine
相同的序列语义。

## 生成代码时真正要紧的规则

- **写之前先看不支持的清单。** 不支持的调用是这里最贵的错误：大多数能编译通过，然后默默返回 `na`，脚本看起来完全正确，却什么也画不出来。
- **`request.security()` 对图表自身品种的高周期有效。** `request.security(syminfo.tickerid, "240", close)` 给出最近一根已收盘的 4 小时 K 线的收盘价，表达式也可以是一次 `ta.*` 调用。换成别的**品种**仍然返回 na：引擎手里只有图表的 K 线，不会去取别的品种。
- **没有未来函数。** 回测的撮合引擎绝不会用未来的数据成交订单：市价单在*下一根 K 线开盘*成交。
- **成本是真的。** 每次成交都按 `strategy()` 里声明的手续费和滑点扣费。一套零成本时盈利的策略，加上这些成本可能就不盈利了。
- **止损单和限价单沿着 K 线成交**，顺序是开盘价、离开盘更近的极值、更远的极值、收盘价。价格跳空越过订单时按开盘价成交。
- **用 `=` 声明，用 `:=` 重新赋值。** 需要跨 K 线保留的状态用 `var`。
- **缩进是四个空格。** Pine 没有大括号，`if`/`for`/`while`/`switch` 的语句块是缩进块。
- **命名参数要放在最后。** 一旦写了 `name=`，后面每个参数都必须带名字：`plotshape(series=x, title="t", style=shape.circle)` 合法，`plotshape(x, "t", style=…)` 不合法。命名参数后面再跟位置参数会让脚本带着语法错误停下来。
- **平仓单不能在发出它的那根 K 线上触发。** 市价 `strategy.entry` 在*下一根 K 线开盘*成交，所以写在那根 K 线上的 `strategy.exit` 最早只能从下一根开始成交。发出它的那根 K 线上价格已经跌破止损的，不会按对你不利的方式成交。
- **两条腿的平仓只触发一次。** `strategy.exit(stop=…, limit=…)` 的其中一条腿成交时，另一条会一起取消：是一笔交易，不会是两笔。如果一根 K 线两个价位都碰到，沿 K 线走势先碰到的那个算数。
- **移动止损：** `strategy.exit(trail_points=N, trail_offset=M)`。两者都以**tick**计，不是价格单位。`trail_offset` 是止损生效之前需要先走出的盈利（tick 数），`trail_points` 是与已到过的最好价格之间保留的距离。止损只会朝对你有利的方向移动，而且只在已收盘的 K 线上移动。

## 函数参考

各个签名及其作用。参数顺序就是书写顺序。

### 语言

Deepwick Script 运行 Pine Script 的一个子集，包括枚举、用户自定义类型、方法和 map；//@version 这一行不会被强制校验。脚本按 K 线逐根运行，从最老的一根到最新的一根，每个变量都保留自己的历史。

- `x = expr / x := expr` — 声明一个变量，然后用 := 重新赋值。名字前面可以加一个可选的类型（int、float、bool、string、color、series、simple、const、line、label）。
- `var / varip` — 在第一根 K 线上初始化一次，之后各根 K 线沿用这个值。由于脚本运行在已收盘的 K 线上，varip 的行为和 var 一样。
- `x[n]` — 历史运算符：n 根之前 x 的值（第一根之前为 na）。
- `if / else` — 条件块，缩进四个空格。if 也可以当作表达式使用。
- `cond ? a : b` — 三元运算符。
- `switch` — 多路分支，可以带一个用于比较的值，也可以不带。
- `for i = a to b [by step]` — 计数循环。支持 break 和 continue。
- `while cond` — 条件成立时持续循环。
- `f(x, y) => expr` — 用户自定义函数，可以写在一行，也可以写成缩进块并返回最后一个表达式。和 Pine 一样，每个调用位置各自保留 ta.* 的状态。
- `[a, b] = f()` — 元组：函数可以返回多个值，ta.macd() 和 ta.bb() 这类内置函数就是这样。
- `and / or / not` — 逻辑运算符。算术：+ - * / %；比较：== != < <= > >=。

### 声明

- `indicator(title, shorttitle, overlay, precision)` (study) — 声明一个指标：它在图上绘制，没有可回测的对象。study() 作为别名也可以。
- `strategy(title, overlay, initial_capital, default_qty_type, default_qty_value, commission_type, commission_value, slippage, pyramiding)` — 声明一个策略。默认值：initial_capital 100000、每单 1 张合约、手续费 0、滑点 0 个 tick、金字塔加仓 1。process_orders_on_close 等其他参数会被忽略。

### 输入

输入会显示在编辑器旁边和指标的设置里，这样不用改代码就能调整它们。

- `input.int(defval, title, minval, maxval, step)` — 整数。
- `input.float(defval, title, minval, maxval, step)` — 小数。
- `input.bool(defval, title)` — 复选框。
- `input.string(defval, title, options)` — 文本，或者一组选项。
- `input.session(defval, title)` — 一个交易时段，比如 "0930-1600"，或者一组星期，比如 "23456"。把它传给 session.ismarket() 和其它 session.* 判断。
- `input.source(defval, title)` — 一个价格来源：open、high、low、close、hl2、hlc3、ohlc4 或 hlcc4。
- `input.color(defval, title)` — 取色器。
- `input(defval, title)` — 通用输入，类型由默认值决定。

### K 线数据与时间

时间是 UTC 毫秒。hour() 和其它时间函数可以传入一个时间；hour() 还可以传入一个时区，取自固定的偏移量列表，不含夏令时。

- `open, high, low, close, volume` (open, high, low, close, volume) — 当前 K 线的价格和成交量。
- `hl2, hlc3, ohlc4, hlcc4` (hl2, hlc3, ohlc4, hlcc4) — 常用的价格均值。
- `bar_index, last_bar_index` (bar_index, last_bar_index) — 当前 K 线的序号（0 是最老的一根）和最后一根的序号。
- `time, time_close` (time, time_close) — K 线的开盘和收盘时间。作为函数 —— time("D")、time(timeframe.period, "0000-0900:23456", "UTC") —— 返回包含当前这根的高周期 K 线的开始（或结束）时间；如果这根 K 线在时段之外，则返回 na。时段写法："HHMM-HHMM"，也可以跨夜，逗号分隔多个窗口，冒号后可跟星期（1 = 周日 … 7 = 周六），以及 "24x7"。
- `timeframe.change(timeframe)` — 在每个新周期的第一根 K 线上为真，例如 timeframe.change("D") 在每天的第一根上为真（每周从周一开始）。
- `timestamp(timezone?, year, month, day, hour, minute, second)` — 由各部分组成毫秒时间，或由日期字符串得到：timestamp("2026-01-05T09:30:00Z")。
- `dayofweek.sunday … dayofweek.saturday` (dayofweek.monday, dayofweek.tuesday, dayofweek.wednesday, dayofweek.thursday, dayofweek.friday, dayofweek.saturday) — 用来和 dayofweek（1 … 7）比较的星期常量。
- `session.ismarket, isfirstbar, islastbar, ispremarket, ispostmarket` (session.ismarket, session.isfirstbar, session.islastbar, session.ispremarket, session.ispostmarket) — 时段状态。这里的市场几乎全天交易，所以每根 K 线都在交易时段内；isfirstbar / islastbar 标出每个 UTC 日的第一根和最后一根。
- `year, month, weekofyear, dayofmonth, dayofweek, hour, minute, second` (year, month, weekofyear, dayofmonth, dayofweek, hour, minute, second) — K 线时间的日历字段；也可以传入一个时间来调用，例如 hour(time, "America/New_York")。dayofweek：1 = 周日 … 7 = 周六。
- `barstate.isfirst, islast, isnew, isconfirmed, ishistory, isrealtime` (barstate.isfirst, barstate.islast, barstate.isnew, barstate.isconfirmed, barstate.ishistory, barstate.isrealtime) — 脚本在 K 线历史中的位置。
- `timeframe.period, multiplier, isintraday, isdaily, isweekly, ismonthly` (timeframe.period, timeframe.multiplier, timeframe.isintraday, timeframe.isdaily, timeframe.isweekly, timeframe.ismonthly) — 图表的周期。
- `syminfo.ticker, tickerid, mintick, pointvalue` (syminfo.ticker, syminfo.tickerid, syminfo.mintick, syminfo.pointvalue) — 图表的品种、最小价格变动和一个点的价值。

### 技术分析（ta.*）

和 Pine 一样，每个调用位置各自保留状态：写在两行里的两次 ta.ema() 调用是两个互不相干的平均值。K 线不够多之前，结果是 na。

- `ta.sma(source, length)` — 简单移动平均。
- `ta.ema(source, length)` — 指数移动平均。
- `ta.rma(source, length)` — Wilder 移动平均，RSI 和 ATR 用的是它。
- `ta.wma(source, length)` — 加权移动平均。
- `ta.vwma(source, length)` — 成交量加权移动平均。
- `ta.hma(source, length)` — Hull 移动平均。
- `ta.linreg(source, length, offset)` — 线性回归线的数值。
- `ta.vwap(source)` — 成交量加权平均价，每天 00:00 UTC 重新开始。
- `ta.rsi(source, length)` — 相对强弱指数，0 到 100。
- `ta.macd(source, fastlen, slowlen, siglen)` — 返回 [macd, signal, histogram]。
- `ta.stoch(source, high, low, length)` — 随机指标 %K，0 到 100。
- `ta.cci(source, length)` — 商品通道指数。
- `ta.mfi(series, length)` — 资金流量指数。
- `ta.wpr(length)` — 威廉指标 %R，-100 到 0。
- `ta.dmi(diLength, adxSmoothing)` — 返回 [+DI, -DI, ADX]。
- `ta.supertrend(factor, atrPeriod)` — 返回 [supertrend, direction]；上涨趋势中 direction 为 -1，下跌趋势中为 1。
- `ta.sar(start, inc, max)` — 抛物线 SAR。
- `ta.mom(source, length)` — 动量：source 减去 length 根之前的 source。
- `ta.roc(source, length)` — 变动率，以百分比表示。
- `ta.change(source, length)` — 与 length 根之前的差值（默认为 1）。
- `ta.tr / ta.tr(handle_na)` — 真实波幅。
- `ta.atr(length)` — 平均真实波幅（Wilder）。
- `ta.bb(series, length, mult)` — 布林带：返回 [middle, upper, lower]。
- `ta.bbw(series, length, mult)` — 布林带宽度：(upper - lower) / middle。
- `ta.kc(series, length, mult)` — 肯特纳通道：返回 [middle, upper, lower]，使用真实波幅的 EMA。
- `ta.stdev(source, length, biased)` — 标准差。
- `ta.variance(source, length, biased)` — 方差。
- `ta.dev(source, length)` — 平均绝对偏差。
- `ta.median(source, length)` — 中位数。
- `ta.highest(source, length) / ta.highest(length)` — 最近 length 根里的最高值（默认为 high）。
- `ta.lowest(source, length) / ta.lowest(length)` — 最近 length 根里的最低值（默认为 low）。
- `ta.highestbars(source, length)` — 相对最高值的偏移：0 或负数。
- `ta.lowestbars(source, length)` — 相对最低值的偏移：0 或负数。
- `ta.rising(source, length)` — 如果 source 高于它之前 length 个值中的每一个，则为真。
- `ta.falling(source, length)` — 如果 source 低于它之前 length 个值中的每一个，则为真。
- `ta.crossover(source1, source2)` — 在 source1 上穿 source2 的那根 K 线上为真。
- `ta.crossunder(source1, source2)` — 在 source1 下穿 source2 的那根 K 线上为真。
- `ta.cross(source1, source2)` — 任意方向的交叉都为真。
- `ta.pivothigh(source, leftbars, rightbars)` — 枢轴高点的价格，要等枢轴之后 rightbars 根才能确定，在此之前是 na。source 可选（默认为 high）。
- `ta.pivotlow(source, leftbars, rightbars)` — 枢轴低点的价格，要等枢轴之后 rightbars 根才能确定，在此之前是 na。source 可选（默认为 low）。
- `ta.valuewhen(condition, source, occurrence)` — 在最近第 occurrence 根满足 condition 的 K 线上，source 的取值。
- `ta.barssince(condition)` — 自 condition 上一次为真以来经过的 K 线数。
- `ta.cum(source)` — 从第一根 K 线开始的累计值。

### 策略（strategy.*）

市价单在下一根 K 线开盘时成交。止损单和限价单沿着这根 K 线成交：开盘价，然后是离开盘更近的那个极值，再是另一个极值，最后是收盘价。如果价格跳空越过订单，就按开盘价成交。每次成交都收手续费；滑点适用于市价单和止损单。

- `strategy.entry(id, direction, qty, limit, stop, comment)` — 开仓或加仓；没有指定 limit 或 stop 时就是市价单。
- `strategy.order(id, direction, qty, limit, stop, comment)` — 参数和 strategy.entry() 相同。
- `strategy.exit(id, from_entry, qty_percent, profit, limit, loss, stop, trail_points, trail_offset, comment)` — 针对某次入场的止盈、止损和移动止损：止盈和止损以 tick 计，limit 和 stop 用价格。trail_points 是距已到过的最好价格的距离（以 tick 计），trail_offset 是移动止损生效之前需要先走出的盈利（以 tick 计）。止损只会向对你有利的方向移动，而且只在已收盘的 K 线上移动，所以任何一根 K 线都不可能触发它自己的最高价所设下的止损。
- `strategy.close(id, comment, qty_percent)` — 在下一根 K 线以市价平掉一次入场。
- `strategy.close_all(comment)` — 平掉所有持仓。
- `strategy.cancel(id) / strategy.cancel_all()` (strategy.cancel_all) — 撤掉未成交的订单。
- `strategy.position_size, position_avg_price` (strategy.position_size, strategy.position_avg_price) — 当前持仓（多头为正，空头为负）及其均价。
- `strategy.opentrades.entry_bar_index(n), entry_price, entry_time, entry_id, size, profit, commission, max_runup, max_drawdown` (strategy.opentrades.entry_price, strategy.opentrades.entry_time, strategy.opentrades.entry_id, strategy.opentrades.size, strategy.opentrades.profit, strategy.opentrades.commission, strategy.opentrades.max_runup, strategy.opentrades.max_drawdown) — 第 n 笔未平仓交易的详情（0 为最老的一笔）；没有则为 na。空头的 size 为负数。例如持有 10 根 K 线后平仓：bar_index - strategy.opentrades.entry_bar_index(0) >= 10。
- `strategy.closedtrades.entry_bar_index(n), exit_bar_index, entry_price, exit_price, entry_time, exit_time, entry_id, size, profit, commission, max_runup, max_drawdown` (strategy.closedtrades.exit_bar_index, strategy.closedtrades.entry_price, strategy.closedtrades.exit_price, strategy.closedtrades.entry_time, strategy.closedtrades.exit_time, strategy.closedtrades.entry_id, strategy.closedtrades.size, strategy.closedtrades.profit, strategy.closedtrades.commission, strategy.closedtrades.max_runup, strategy.closedtrades.max_drawdown) — 第 n 笔已平仓交易的详情（0 为最老的一笔；最后一笔是 strategy.closedtrades - 1）。
- `strategy.equity, netprofit, openprofit, grossprofit, grossloss, initial_capital` (strategy.equity, strategy.netprofit, strategy.openprofit, strategy.grossprofit, strategy.grossloss, strategy.initial_capital) — 账户数值。
- `strategy.closedtrades, opentrades, wintrades, losstrades` (strategy.closedtrades, strategy.opentrades, strategy.wintrades, strategy.losstrades) — 交易笔数。
- `strategy.long, strategy.short` (strategy.long, strategy.short) — 方向。
- `strategy.fixed, strategy.cash, strategy.percent_of_equity` (strategy.fixed, strategy.cash, strategy.percent_of_equity) — default_qty_type 的取值。
- `strategy.commission.percent, cash_per_order, cash_per_contract` (strategy.commission.percent, strategy.commission.cash_per_order, strategy.commission.cash_per_contract) — commission_type 的取值。

### 绘图与提醒

- `plot(series, title, color, linewidth, style)` — 在图表上或独立窗格中绘制一条序列。
- `plotshape(series, title, style, location, color, text)` — 在 series 为真的那些 K 线上绘制图形。
- `plotchar(series, title, char, location, color)` — 在 series 为真的那些 K 线上绘制字符。
- `hline(price, title, color, linestyle)` — 固定水平上的水平线。
- `fill(plot1, plot2, color)` — 在两条绘图线或两条 hline 之间填充。
- `bgcolor(color)` — 给 K 线背景上色。
- `barcolor(color)` — 给 K 线本身上色。
- `alertcondition(condition, title, message)` — 声明一个条件，可以把它变成邮件、Telegram、Discord 或 webhook 提醒。
- `plot.style_*` (plot.style_line, plot.style_linebr, plot.style_stepline, plot.style_histogram, plot.style_columns, plot.style_circles, plot.style_cross, plot.style_area) — line、linebr、stepline、histogram、columns、circles、cross、area。
- `hline.style_*` (hline.style_solid, hline.style_dashed, hline.style_dotted) — solid、dashed、dotted。
- `shape.*` (shape.triangleup, shape.triangledown, shape.arrowup, shape.arrowdown, shape.circle, shape.xcross, shape.cross, shape.diamond, shape.square, shape.flag, shape.labelup, shape.labeldown) — triangleup, triangledown, arrowup, arrowdown, circle, xcross, cross, diamond, square, flag, labelup, labeldown.
- `location.*` (location.abovebar, location.belowbar, location.top, location.bottom, location.absolute) — abovebar、belowbar、top、bottom、absolute。
- `size.*` (size.auto, size.tiny, size.small, size.normal, size.large, size.huge) — auto、tiny、small、normal、large、huge。可以接受，但图形只按一种大小绘制。

### 线与方框

- `line.new(x1, y1, x2, y2, extend, color, style, width)` — 在两个 K 线序号和两个价格之间画一条线，返回它的 id。
- `line.set_x1, set_y1, set_x2, set_y2, set_xy1, set_xy2, set_color, set_style, set_width` (line.set_x1, line.set_y1, line.set_x2, line.set_y2, line.set_xy1, line.set_xy2, line.set_color, line.set_style, line.set_width) — 修改一条线。
- `line.delete(id)` — 删除一条线。
- `box.new(left, top, right, bottom, border_color, bgcolor, extend)` — 画一个矩形，返回它的 id。
- `box.set_left, set_top, set_right, set_bottom, set_bgcolor, set_border_color, set_extend` (box.set_left, box.set_top, box.set_right, box.set_bottom, box.set_bgcolor, box.set_border_color, box.set_extend) — 修改一个方框。
- `box.delete(id)` — 删除一个方框。
- `line.style_*, box.style_*` (line.style_solid, line.style_dashed, line.style_dotted, box.style_solid, box.style_dashed, box.style_dotted) — solid、dashed、dotted。
- `extend.*` (extend.none, extend.left, extend.right, extend.both) — none、left、right、both。

### 数学、字符串与颜色

- `math.abs, ceil, floor, round(number, precision), sign, sqrt, exp, log, log10, pow(base, exponent)` (math.abs, math.ceil, math.floor, math.round, math.sign, math.sqrt, math.exp, math.log, math.log10, math.pow) — 算术。
- `math.max(...), math.min(...), math.avg(...)` (math.min, math.avg) — 对任意多个值。
- `math.sum(source, length)` — 最近 length 根 K 线的总和。
- `math.pi, math.e` (math.pi, math.e) — 常量。
- `na, na(x), nz(x, replacement), fixnan(x)` (na, nz, fixnan) — 缺失值、对它的判断、对它的替换，以及最后一个非 na 的值。
- `int(x), float(x), bool(x)` (float, bool) — 类型转换。
- `str.tostring(value, format), str.format(text, ...), str.length(s), str.contains(s, part)` (str.format, str.length, str.contains) — 字符串。str.format 用参数替换 {0}、{1}…。
- `color.new(color, transp), color.rgb(red, green, blue, transp)` (color.rgb) — 构造一种颜色；透明度从 0 到 100。
- `color.*` (color.red, color.green, color.blue, color.orange, color.yellow, color.purple, color.aqua, color.lime, color.fuchsia, color.teal, color.maroon, color.navy, color.olive, color.gray, color.silver, color.white, color.black) — red, green, blue, orange, yellow, purple, aqua, lime, fuchsia, teal, maroon, navy, olive, gray, silver, white, black.

### 数组（array.*）

- `array.new_float, new_int, new_bool, new_string, new_color, new_line, new_box, new_label, new_table(size)` (array.new_float, array.new_int, array.new_bool, array.new_string, array.new_color, array.new_line, array.new_box, array.new_label, array.new_table) — 创建一个数组。
- `array.get, set, insert, push, pop, shift, unshift` (array.get, array.set, array.insert, array.push, array.pop, array.shift, array.unshift) — 读取和修改元素。
- `array.size, first, last, sum, avg, min, max, stdev` (array.size, array.first, array.last, array.sum, array.avg, array.min, array.max, array.stdev) — 长度与统计。

### Map 与用户自定义类型

支持用户自定义类型和 `map.<fn>` 集合。两者都是顶层声明；作用于某个值的方法用 `obj.method(args...)` 的写法。

- `enum Name
    Member
    Member = N
    ...` — 顶层枚举声明。没有写值的成员从 0 开始自动递增；显式值可以是数字或字符串。在任何表达式位置都可以用 `Name.Member` 访问。枚举值就是普通的数字（或字符串），所以可以直接和比较运算符配合，也可以不转换就传给 `int()`。
- `type Name
    field1
    field2: int
    field3 = default` — 顶层用户自定义类型。字段一行一个；`: type` 和 `= default` 这两部分为了向前兼容被接受，但目前还没有校验。用 `Type.new(arg1, arg2, ...)` 构造，用 `instance.field` 读取字段。
- `m = map.new<int, float>()` (map.new) — 创建一个空的 map。类型参数 `<K, V>` 会被接受，但运行时忽略。
- `m = map.put(m, key, value)` (map.put) — 设置一个键。返回这个 map，所以调用可以链式书写或重新赋值。
- `v = map.get(m, key)` (map.get) — 读取一个值。键不存在时返回 na。
- `n = map.size(m)` (map.size) — 条目数量。
- `keys = map.keys(m), values = map.values(m)` (map.keys, map.values) — 以 Pine 数组返回键或值（按插入顺序）。
- `map.contains(m, key), map.remove(m, key)` (map.remove) — 成员判断和删除。两者都返回这个 map。

## 还不可用

调用引擎不认识的函数时，脚本会带着「Unknown function」以及行号和列号停下来。

- `label.new(), table.new()`: 还不可用。线和方框可以。
- `import, matrix.*, array.new<type>()`: 库、矩阵和带类型的数组构造函数还没有实现。
- `strategy.risk.*`: 风控规则（max_position_size、max_intraday_loss、max_drawdown、allow_entry_in）还不支持。strategy.exit() 里的移动止损支持：用 trail_points 和 trail_offset。

## 可运行的示例

随附的、可以在这个引擎上编译通过的脚本：

**RSI Mean Reversion**

```pine
//@version=5
strategy("RSI Mean Reversion", overlay=false, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=10, commission_type=strategy.commission.percent, commission_value=0.1)
len = input.int(14, "RSI length", minval=2)
oversold = input.float(30, "Oversold")
exitLevel = input.float(50, "Exit level")
stopPct = input.float(2, "Stop loss %", minval=0, step=0.1)
tpPct = input.float(6, "Take profit %", minval=0, step=0.1)
if strategy.position_size > 0
    strategy.exit("Risk", stop=stopPct > 0 ? strategy.position_avg_price * (1 - stopPct / 100) : na, limit=tpPct > 0 ? strategy.position_avg_price * (1 + tpPct / 100) : na)
r = ta.rsi(close, len)
if strategy.position_size == 0 and r < oversold
    strategy.entry("Long", strategy.long)
if strategy.position_size > 0 and r > exitLevel
    strategy.close("Long", comment="RSI exit")
plot(r, "RSI", color=color.purple)
hline(oversold, "Oversold", color=color.green)
hline(exitLevel, "Exit", color=color.gray)
```

**MACD Crossover**

```pine
//@version=5
strategy("MACD Crossover", overlay=false, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=10, commission_type=strategy.commission.percent, commission_value=0.1)
fast = input.int(12, "Fast", minval=1)
slow = input.int(26, "Slow", minval=2)
sig = input.int(9, "Signal", minval=1)
stopPct = input.float(2, "Stop loss %", minval=0, step=0.1)
tpPct = input.float(6, "Take profit %", minval=0, step=0.1)
if strategy.position_size > 0
    strategy.exit("Risk", stop=stopPct > 0 ? strategy.position_avg_price * (1 - stopPct / 100) : na, limit=tpPct > 0 ? strategy.position_avg_price * (1 + tpPct / 100) : na)
[m, s, h] = ta.macd(close, fast, slow, sig)
if ta.crossover(m, s)
    strategy.entry("Long", strategy.long)
if ta.crossunder(m, s)
    strategy.close("Long", comment="MACD cross")
plot(h, "Histogram", color=h >= 0 ? color.new(color.green, 40) : color.new(color.red, 40), style=plot.style_columns)
plot(m, "MACD", color=color.orange)
plot(s, "Signal", color=color.blue)
```

**Bollinger Bounce**

```pine
//@version=5
strategy("Bollinger Bounce", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=10, commission_type=strategy.commission.percent, commission_value=0.1)
len = input.int(20, "Length", minval=2)
mult = input.float(2, "StdDev", minval=0.5, step=0.1)
stopPct = input.float(2, "Stop loss %", minval=0, step=0.1)
tpPct = input.float(6, "Take profit %", minval=0, step=0.1)
if strategy.position_size > 0
    strategy.exit("Risk", stop=stopPct > 0 ? strategy.position_avg_price * (1 - stopPct / 100) : na, limit=tpPct > 0 ? strategy.position_avg_price * (1 + tpPct / 100) : na)
[basis, upper, lower] = ta.bb(close, len, mult)
if strategy.position_size == 0 and close <= lower
    strategy.entry("Long", strategy.long)
if strategy.position_size > 0 and close >= basis
    strategy.close("Long", comment="Back to mean")
u = plot(upper, "Upper", color=color.blue)
plot(basis, "Basis", color=color.gray)
l = plot(lower, "Lower", color=color.blue)
fill(u, l, color=color.new(color.blue, 92))
```

## Elsewhere

- Human reference: https://deepwick.com/zh-CN/docs/script
- Try a script with no signup: https://deepwick.com/try
