# Language Tour

> Language Tour is a strategy that trades EURUSD and GBPUSD on 15-minute bars. It holds at most 3 open trades (2 per side), reverses on an opposite sign

Source: https://algobarsx.com/docs/ex-08-language-tour/

```algobarsx
algobarsx 1
# Exercises every construct in spec sections 3-16.
strategy "Language Tour"
    markets: EURUSD, GBPUSD
    bars: 15m
    evaluate: bar_close
    max_open: 3
    max_open_per_side: 2
    direction: both
    opposite: reverse
    pyramiding: 3
    min_distance: 20 pips
    max_daily_loss: 3%
    max_drawdown: 10%
    trade_only: within sessions london, new_york

use indicator "Trend Ribbon" v3 as ribbon (fast: 10, slow: 30)
use library "Quant Toolkit" v2 as qt

input fast = 20, label: "Fast length", min: 2, max: 500, group: "Trend"
input source = close, label: "Source"
input higher_tf = 4h, label: "Higher timeframe"
input session = "london", options: ["london", "new_york", "asia"]
input risk = 1%, min: 0.1%, max: 5%, step: 0.1%
input show_zones = true, group: "Display"
input zone_color = blue.fade(70), group: "Display", visible_if: show_zones

const RISK_CAP = 2%

type Level:
    price: price
    touched: int = 0
    formed_at: time

enum Regime: trending, ranging, volatile

fn swing_strength(len: int) -> number:
    up = highest(high, len) - close
    down = close - lowest(low, len)
    return (down - up) / atr(14)

action fn enter_long(size_risk: percent = 1%) -> bool:
    buy risk: size_risk, stop: 20 pips, target: 2R
    return true

state triggers = 0
state last_entry: price = na
state regime = Regime.ranging
state levels: list<Level> = []

trend_up = ema(close, 50) > ema(close, 200)
distance = (source - ema(source, fast)) / atr(14)
threshold: number = 1.5
h4 = bars(bars: higher_tf)
gold = bars(XAUUSD, bars: 15m)
gold_atr = atr(14, on: gold)
cov = data.coverage(EURUSD, bars: range(10))
spread_z = zscore(log(close_of(EURUSD) / close_of(GBPUSD)), 100)
first_hour = time_of_day between 08:00 and 09:00
recent_high = intrabar(1m).high.max()
kelly = qt.kelly_fraction(0.55, 1.8)
power = 2 ** 3 ** 2
in_window = hour in 8..11

if regime == Regime.trending:
    risk_now = 1%
elif regime == Regime.volatile:
    risk_now = 0.5%
else:
    risk_now = 0.25%

for level in levels:
    if close > level.price:
        level.touched += 1

for i in 0..50:
    if i > 10:
        break
    continue

match regime:
    Regime.trending: log "trending"
    Regime.ranging: log "ranging"

levels.push(Level(price: high, formed_at: time))
levels = levels.filter(l => l.touched == 0).keep_last(50)
ranked = levels.sort_by((a, b) => a.price - b.price)

confirmations long_setup:
    trend: trend_up
    momentum: rsi(close, 14) > 55
    volume: volume > sma(volume, 20) * 1.5
    structure: break_of_structure(direction: up)
    higher_tf_trend: h4.close > ema(h4.close, 50)
    ribbon_up: ribbon.up
    require: at least 5

sequence liquidity_grab within 30 bars:
    step sweep: low < lowest(low, 20)[1]
    step reclaim: close > sweep.high
    step retest: low <= reclaim.close and close > reclaim.close
    reset_if: close < sweep.low

when long_setup.passed as long_entry every 4th:
    buy risk: risk, stop: atr(14) * 1.5, target: 3R

when starts(long_setup.passed) skip first 3 max 2 per day cooldown 30m:
    triggers += 1
    if triggers % 4 == 0:
        buy risk: 0.5%, stop: atr(14) * 1.5, target: 3R

when liquidity_grab.completed from 08:00 to 11:00 Europe/London:
    buy risk: 1%, stop: liquidity_grab.sweep.low - 3 points, target: 2R + 5 pips, tag: "breakout":
        breakeven at: 1R, offset: 2 pips
        partial 30% at: 1.5R
        partial 30% at: 2.5R
        trail by: atr(14), after: 2R
        exit after: 48 bars
        exit when: crosses_below(close, ema(close, 20))

when crosses_below(close, ema(close, 50)) cooldown 5 bars:
    sell risk: $200, stop: highest(high, 10) + 2 pips, target: lowest(low, 50)

when was(trend_up, within: 5 bars) and held(close > open, for: 3 bars) every bar:
    buy limit: lowest(low, 5), size: 1 lot, expires: 10 bars
    buy stop: high + 2 pips, risk: 0.5%, stop_loss: low - 2 pips, target: 2R, ghost: true
    sell market: GBPUSD, size: 0.3 lots

when history.today.pnl < -(2% of account.balance) or account.margin_level < 150%: close_all

for trade in trades.open(tag: "breakout"):
    if trade.r >= 3 and rsi(close, 14) > 75:
        close trade, size: 50%

for trade in trades.open(side: long):
    modify trade, stop: trade.entry_price

cancel orders.pending(tag: "grid")

on start:
    log "starting on {market.symbol}"

on bar close:
    log "bar {bar.index}"

on fill(order):
    log "filled {order.size}"

on exit(trade):
    log "{trade.tag} closed at {trade.r:0.00}R after {long_entry.triggers} triggers"

on session open "new_york":
    log "New York is open"

on day change:
    triggers = 0

on render(canvas):
    for z in levels:
        shape = canvas.path()
        shape.move_to(z.formed_at, z.price)
        shape.line_to(canvas.last_bar, z.price)
        shape.stroke(zone_color, width: 1)
        canvas.text("{z.touched}x", at: (canvas.last_bar, z.price), align: right)

plot ema(close, fast) as fast_line, color: if trend_up then green else red, width: 2
plot (high + low) / 2, color: gray, style: step
fill ribbon.fast, ribbon.slow, color: green.fade(80)
hline 70, style: dashed, color: #22c55e
mark arrow_up, at: below, when: crosses_above(close, ema(close, fast)), color: green
label "Entry", at: (bar.index, high)
line from: (bar.index - 20, lowest(low, 20)), to: (bar.index, lowest(low, 20)), extend: right
box id: "range", from: (bar.index - 10, highest(high, 10)), to: (bar.index, lowest(low, 10)), color: blue.fade(85)
bar_color if close > open then green else red
background red.fade(90), when: regime == Regime.volatile
profile rows: 24, range: session, side: right
fib from: (bar.index - 50, lowest(low, 50)), to: (bar.index, highest(high, 50))
dashboard position: top_right, rows: [["Regime", "{regime}"], ["Triggers", "{triggers}"]]
```
What this script says

Language Tour is a strategy that trades EURUSD and GBPUSD on 15-minute bars. It holds at most 3 open trades (2 per side), reverses on an opposite signal, adds up to 3 entries in the same direction, keeps at least 20 pips between entries, stops for the day after losing 3%, stops trading after a 10% drawdown and trades only during the London and New York sessions.

It uses the indicator "Trend Ribbon" (version 3) as `ribbon`, with `fast` set to 10 and `slow` set to 30.

It uses the library "Quant Toolkit" (version 2) as `qt`.

You can change 7 inputs: `fast` (default 20, shown as "Fast length"), `source` (default close, shown as "Source"), `higher_tf` (default 4h, shown as "Higher timeframe"), `session` (default "london"), `risk` (default 1%), `show_zones` (default true) and `zone_color` (default blue.fade(70)).

It defines the constant `RISK_CAP` as 2%.

It defines `swing_strength(len)`, which returns a number and the action `enter_long(size_risk)`, which returns true or false.

It remembers `triggers`, `last_entry`, `regime` and `levels` from one bar to the next.

It calculates `trend_up` as whether the 50-bar EMA of the close is above the 200-bar EMA of the close, `distance` as (`source` minus the EMA of `source` over `fast` bars) divided by the 14-bar ATR, `threshold` as 1.5, `h4` as `higher_tf` bars, `gold` as XAUUSD 15-minute bars, `gold_atr` as the 14-bar ATR of `gold`, `cov` as the data.coverage (symbol EURUSD, bars the range (size 10)), `spread_z` as the 100-bar z-score of the logarithm of the close of EURUSD divided by the close of GBPUSD, `first_hour` as whether the time of day is between 08:00 and 09:00, `recent_high` as `intrabar(1m).high.max()`, `kelly` as `qt.kelly_fraction(0.55, 1.8)`, `power` as 2 to the power of 3 to the power of 2 and 3 more values.

`long_setup` passes when at least 5 of these 6 conditions are true: `trend` (`trend_up`); `momentum` (the 14-bar RSI is above 55); `volume` (volume is above 1.5 × the 20-bar SMA of volume); `structure` (a bullish break of structure); `higher_tf_trend` (`h4.close` is above the 50-bar EMA of `h4.close`); `ribbon_up` (`ribbon.up`).

`liquidity_grab` completes when these steps happen in order within 30 bars: `sweep`, when the low is below the previous bar's lowest low of the last 20 bars; then `reclaim`, when the close is above `sweep.high`; then `retest`, when the low is at or below `reclaim.close` and the close is above `reclaim.close`. It starts over if the close is below `sweep.low`.

When `long_setup` passes (on every 4th time), it buys at market, risking `risk` of the balance, with a stop 1.5 × the 14-bar ATR from the entry and with a target 3R from the entry.

When `long_setup` passes becomes true (ignoring the first 3 times, at most 2 times per day and waiting at least 30 minutes between actions), it adds 1 to `triggers`; it also checks whether `triggers` modulo 4 is 0 and, if so, buys at market, risking 0.5% of the balance, with a stop 1.5 × the 14-bar ATR from the entry and with a target 3R from the entry.

When `liquidity_grab` completes (between 08:00 and 11:00 Europe/London time), it buys at market, risking 1% of the balance, with a stop at the low of the `sweep` step minus 3 points, with a target 2R plus 5 pips from the entry and tagged "breakout"; once open, it moves the stop to breakeven at 1R plus 2 pips, closes 30% at 1.5R, closes 30% at 2.5R, trails the stop by the 14-bar ATR once the trade reaches 2R, exits after 48 bars and exits when the close crosses below the 20-bar EMA of the close.

When the close crosses below the 50-bar EMA of the close (waiting at least 5 bars between actions), it sells at market, risking $200, with a stop at the highest high of the last 10 bars plus 2 pips and with a target at the lowest low of the last 50 bars.

When `trend_up` at some point within the last 5 bars and the close is above the open for 3 bars in a row (on every bar while it holds), it buys with a limit order at the lowest low of the last 5 bars, with a size of 1 lot and expiring after 10 bars; it also buys with a stop order at the high plus 2 pips, risking 0.5% of the balance, with a stop-loss at the low minus 2 pips, with a target 2R from the entry and kept hidden from the broker until it triggers; it also sells GBPUSD at market, with a size of 0.3 lots.

When today's closed profit or loss is below minus 2% of the account balance or the margin level is below 150%, it closes all trades.

When the script starts, it logs "starting on {market.symbol}".

At every bar close, it logs "bar {bar.index}".

When an order fills, it logs "filled {order.size}".

When a trade closes, it logs "{trade.tag} closed at {trade.r:0.00}R after {long_entry.triggers} triggers".

When the New York session opens, it logs "New York is open".

When a new day begins, it sets `triggers` to 0.

Whenever the chart is drawn, it goes through each `z` in `levels` and sets `shape` to `canvas.path()`, moves to a point, draws a line segment, outlines the shape and writes "{z.touched}x" on the chart.

On each bar, it checks whether `regime` is trending and, if so, sets `risk_now` to 1%; otherwise, if `regime` is volatile, sets `risk_now` to 0.5%; otherwise sets `risk_now` to 0.25%.

On each bar, it goes through each `level` in `levels` and checks whether the close is above `level.price` and, if so, adds 1 to `level.touched`.

On each bar, it goes through each `i` in 0 to 50 and checks whether `i` is above 10 and, if so, stops the loop; it also moves on to the next item.

On each bar, it checks `regime`: for trending it logs "trending"; for ranging it logs "ranging".

On each bar, it goes through each `trade` in open trades tagged "breakout" and checks whether `trade.r` is at or above 3 and the 14-bar RSI is above 75 and, if so, closes `trade` (50% of it).

On each bar, it goes through each `trade` in open trades on the long side and moves the stop to `trade.entry_price` for `trade`.

On each bar, it cancels pending orders tagged "grid".

On the chart, it plots the EMA of the close over `fast` bars as `fast_line`, plots (the high plus the low) divided by 2, shades between `ribbon.fast` and `ribbon.slow`, draws a horizontal line at 70, marks arrow up below the bar when the close crosses above the EMA of the close over `fast` bars, labels "Entry", draws a line, draws a box, colors the bars, shades the background when `regime` is volatile, draws a volume profile, draws Fibonacci levels and shows a dashboard.

This description may be incomplete because the script has errors.
