///|
fn direction_label(direction : @domain.Direction) -> String {
  match direction {
    Bullish => "bullish"
    Bearish => "bearish"
    Neutral => "neutral"
  }
}

///|
fn cycle_label(cycle : @domain.CyclePosition) -> String {
  match cycle {
    Spike => "spike"
    MicroChannel => "micro_channel"
    TightChannel => "tight_channel"
    NormalChannel => "normal_channel"
    BroadChannel => "broad_channel"
    TrendingRange => "trending_range"
    TradingRange => "trading_range"
    ExtremeRange => "extreme_range"
    UnknownCycle => "unknown"
  }
}

///|
fn phase_label(phase : @domain.MarketPhase) -> String {
  match phase {
    Stable => "stable"
    Transitioning => "transitioning"
  }
}

///|
fn pattern_label(pattern : @domain.PatternTag) -> String {
  match pattern {
    Wedge => "wedge"
    ReversalAttempt => "reversal_attempt"
    MajorTrendReversal => "major_trend_reversal"
    FinalFlag => "final_flag"
    H1 => "h1"
    H2 => "h2"
    L1 => "l1"
    L2 => "l2"
    BreakoutTest => "breakout_test"
    BreakoutPullback => "breakout_pullback"
    BreakoutFailure => "breakout_failure"
    AlwaysIn => "always_in"
    Barbwire => "barbwire"
    Overlap => "overlap"
    MiddleRange => "middle_range"
    FailedSignal => "failed_signal"
    Triangle => "triangle"
    DoubleTopBottom => "double_top_bottom"
    MeasuredMove => "measured_move"
    UnknownPattern(value) => "unknown:\{value}"
  }
}

///|
fn action_label(action : @domain.DecisionAction) -> String {
  match action {
    NoOrder => "no_order"
    Wait => "wait"
    LimitOrder => "limit_order"
    BreakoutOrder => "breakout_order"
    MarketOrder => "market_order"
  }
}

///|
fn opt_double_label(value : Double?) -> String {
  match value {
    Some(x) => "\{x}"
    None => "null"
  }
}

///|
fn pattern_list(patterns : Array[@domain.PatternTag]) -> String {
  patterns.map(pattern_label).join(", ")
}