示例#1
0
文件: nb.py 项目: vroomzel/vectorbt
def breakout_labels_nb(close: tp.Array2d,
                       window: int,
                       pos_th: tp.MaybeArray[float],
                       neg_th: tp.MaybeArray[float],
                       wait: int = 1,
                       flex_2d: bool = True) -> tp.Array2d:
    """For each value, return 1 if any value in the next period is greater than the
    positive threshold (in %), -1 if less than the negative threshold, and 0 otherwise.

    First hit wins."""
    pos_th = np.asarray(pos_th)
    neg_th = np.asarray(neg_th)
    out = np.full_like(close, 0, dtype=np.float_)

    for col in range(close.shape[1]):
        for i in range(close.shape[0]):
            _pos_th = abs(flex_select_auto_nb(pos_th, i, col, flex_2d))
            _neg_th = abs(flex_select_auto_nb(neg_th, i, col, flex_2d))

            for j in range(i + wait, min(i + window + wait, close.shape[0])):
                if _pos_th > 0 and close[j,
                                         col] >= close[i, col] * (1 + _pos_th):
                    out[i, col] = 1
                    break
                if _neg_th > 0 and close[j,
                                         col] <= close[i, col] * (1 - _neg_th):
                    out[i, col] = -1
                    break

    return out
示例#2
0
文件: nb.py 项目: vroomzel/vectorbt
def local_extrema_apply_nb(close: tp.Array2d,
                           pos_th: tp.MaybeArray[float],
                           neg_th: tp.MaybeArray[float],
                           flex_2d: bool = True) -> tp.Array2d:
    """Get array of local extrema denoted by 1 (peak) or -1 (trough), otherwise 0.

    Two adjacent peak and trough points should exceed the given threshold parameters.

    If any threshold is given element-wise, it will be applied per new/updated extremum.

    Inspired by https://www.mdpi.com/1099-4300/22/10/1162/pdf"""
    pos_th = np.asarray(pos_th)
    neg_th = np.asarray(neg_th)
    out = np.full(close.shape, 0, dtype=np.int_)

    for col in range(close.shape[1]):
        prev_i = 0
        direction = 0

        for i in range(1, close.shape[0]):
            _pos_th = abs(flex_select_auto_nb(pos_th, prev_i, col, flex_2d))
            _neg_th = abs(flex_select_auto_nb(neg_th, prev_i, col, flex_2d))
            if _pos_th == 0:
                raise ValueError("Positive threshold cannot be 0")
            if _neg_th == 0:
                raise ValueError("Negative threshold cannot be 0")

            if direction == 1:
                # Find next high while updating current lows
                if close[i, col] < close[prev_i, col]:
                    prev_i = i
                elif close[i, col] >= close[prev_i, col] * (1 + _pos_th):
                    out[prev_i, col] = -1
                    prev_i = i
                    direction = -1
            elif direction == -1:
                # Find next low while updating current highs
                if close[i, col] > close[prev_i, col]:
                    prev_i = i
                elif close[i, col] <= close[prev_i, col] * (1 - _neg_th):
                    out[prev_i, col] = 1
                    prev_i = i
                    direction = 1
            else:
                # Find first high/low
                if close[i, col] >= close[prev_i, col] * (1 + _pos_th):
                    out[prev_i, col] = -1
                    prev_i = i
                    direction = -1
                elif close[i, col] <= close[prev_i, col] * (1 - _neg_th):
                    out[prev_i, col] = 1
                    prev_i = i
                    direction = 1

            if i == close.shape[0] - 1:
                # Find last high/low
                if direction != 0:
                    out[prev_i, col] = -direction
    return out
示例#3
0
def bn_cont_sat_trend_labels_nb(close,
                                local_extrema,
                                pos_th,
                                neg_th,
                                flex_2d=True):
    """Similar to `bn_cont_trend_labels_nb` but sets each close value to 0/1
    if the percentage change to the next extremum exceeds a threshold set for this value.
    """
    pos_th = np.asarray(pos_th)
    neg_th = np.asarray(neg_th)
    out = np.empty_like(close, dtype=np.float_)

    for col in range(close.shape[1]):
        idxs = np.flatnonzero(local_extrema[:, col])
        if idxs.shape[0] == 0:
            out[:, col] = np.nan
            continue

        for k in range(1, idxs.shape[0]):
            start_i = prev_i = idxs[k - 1]
            end_i = next_i = idxs[k]
            if k == idxs.shape[0] - 1:
                end_i += 1

            _pos_th = abs(flex_select_auto_nb(prev_i, col, pos_th, flex_2d))
            _neg_th = abs(flex_select_auto_nb(prev_i, col, neg_th, flex_2d))
            if _pos_th == 0:
                raise ValueError("Positive threshold cannot be 0")
            if _neg_th == 0:
                raise ValueError("Negative threshold cannot be 0")
            _min = np.min(close[prev_i:next_i + 1, col])
            _max = np.max(close[prev_i:next_i + 1, col])

            for i in range(start_i, end_i):
                if close[next_i, col] > close[prev_i, col]:
                    _start = _max / (1 + _pos_th)
                    _end = _min * (1 + _pos_th)
                    if _max >= _end and close[i, col] <= _start:
                        out[i, col] = 1
                    else:
                        out[i, col] = 1 - (close[i, col] - _start) / (_max -
                                                                      _start)
                else:
                    _start = _min / (1 - _neg_th)
                    _end = _max * (1 - _neg_th)
                    if _min <= _end and close[i, col] >= _start:
                        out[i, col] = 0
                    else:
                        out[i,
                            col] = 1 - (close[i, col] - _min) / (_start - _min)

    return out
示例#4
0
文件: nb.py 项目: vroomzel/vectorbt
def bn_cont_sat_trend_labels_nb(close: tp.Array2d,
                                local_extrema: tp.Array2d,
                                pos_th: tp.MaybeArray[float],
                                neg_th: tp.MaybeArray[float],
                                flex_2d: bool = True) -> tp.Array2d:
    """Similar to `bn_cont_trend_labels_nb` but sets each close value to 0 or 1
    if the percentage change to the next extremum exceeds the threshold set for this range.
    """
    pos_th = np.asarray(pos_th)
    neg_th = np.asarray(neg_th)
    out = np.full_like(close, np.nan, dtype=np.float_)

    for col in range(close.shape[1]):
        idxs = np.flatnonzero(local_extrema[:, col])
        if idxs.shape[0] == 0:
            continue

        for k in range(1, idxs.shape[0]):
            prev_i = idxs[k - 1]
            next_i = idxs[k]

            _pos_th = abs(flex_select_auto_nb(pos_th, prev_i, col, flex_2d))
            _neg_th = abs(flex_select_auto_nb(neg_th, prev_i, col, flex_2d))
            if _pos_th == 0:
                raise ValueError("Positive threshold cannot be 0")
            if _neg_th == 0:
                raise ValueError("Negative threshold cannot be 0")
            _min = np.min(close[prev_i:next_i + 1, col])
            _max = np.max(close[prev_i:next_i + 1, col])

            for i in range(prev_i, next_i):
                if close[next_i, col] > close[prev_i, col]:
                    _start = _max / (1 + _pos_th)
                    _end = _min * (1 + _pos_th)
                    if _max >= _end and close[i, col] <= _start:
                        out[i, col] = 1
                    else:
                        out[i, col] = 1 - (close[i, col] - _start) / (_max -
                                                                      _start)
                else:
                    _start = _min / (1 - _neg_th)
                    _end = _max * (1 - _neg_th)
                    if _min <= _end and close[i, col] >= _start:
                        out[i, col] = 0
                    else:
                        out[i,
                            col] = 1 - (close[i, col] - _min) / (_start - _min)

    return out
示例#5
0
def omega_ratio_nb(returns, ann_factor, risk_free, required_return):
    """2-dim version of `omega_ratio_1d_nb`.

    `risk_free_arr` and `required_return_arr` should be arrays of shape `returns.shape[1]`."""
    risk_free_arr = np.asarray(risk_free)
    required_return_arr = np.asarray(required_return)
    out = np.empty(returns.shape[1], dtype=np.float_)
    for col in range(returns.shape[1]):
        _risk_free = flex_select_auto_nb(0, col, risk_free_arr, True)
        _required_return = flex_select_auto_nb(0, col, required_return_arr,
                                               True)
        out[col] = omega_ratio_1d_nb(returns[:, col],
                                     ann_factor,
                                     risk_free=_risk_free,
                                     required_return=_required_return)
    return out
示例#6
0
文件: nb.py 项目: jingmouren/vectorbt
def rand_choice_nb(from_i: int, to_i: int, col: int, n: tp.MaybeArray[int]) -> tp.Array1d:
    """`choice_func_nb` to randomly pick `n` values from range `[from_i, to_i)`.

    `n` uses flexible indexing."""
    ns = np.asarray(n)
    size = min(to_i - from_i, flex_select_auto_nb(ns, 0, col, True))
    return from_i + np.random.choice(to_i - from_i, size=size, replace=False)
示例#7
0
文件: nb.py 项目: jzay/vectorbt
def rand_choice_nb(from_i, to_i, col, n):
    """`choice_func_nb` to randomly pick `n` values from range `[from_i, to_i)`.

    `n` uses flexible indexing."""
    ns = np.asarray(n)
    return from_i + np.random.choice(to_i - from_i,
                                     size=flex_select_auto_nb(
                                         0, col, ns, True),
                                     replace=False)
示例#8
0
def cum_returns_nb(returns, start_value):
    """2-dim version of `cum_returns_1d_nb`."""
    start_value_arr = np.asarray(start_value)
    out = np.empty_like(returns, dtype=np.float_)
    for col in range(returns.shape[1]):
        _start_value = flex_select_auto_nb(0, col, start_value_arr, True)
        out[:, col] = cum_returns_1d_nb(returns[:, col],
                                        start_value=_start_value)
    return out
示例#9
0
def value_at_risk_nb(returns, cutoff):
    """2-dim version of `value_at_risk_1d_nb`.

    `cutoff_arr` should be an array of shape `returns.shape[1]`."""
    cutoff_arr = np.asarray(cutoff)
    out = np.empty(returns.shape[1], dtype=np.float_)
    for col in range(returns.shape[1]):
        _cutoff = flex_select_auto_nb(0, col, cutoff_arr, True)
        out[col] = value_at_risk_1d_nb(returns[:, col], cutoff=_cutoff)
    return out
示例#10
0
def cum_returns_final_nb(returns, start_value):
    """2-dim version of `cum_returns_final_1d_nb`.

    `start_value_arr` should be an array of shape `returns.shape[1]`."""
    start_value_arr = np.asarray(start_value)
    out = np.empty(returns.shape[1], dtype=np.float_)
    for col in range(returns.shape[1]):
        _start_value = flex_select_auto_nb(0, col, start_value_arr, True)
        out[col] = cum_returns_final_1d_nb(returns[:, col],
                                           start_value=_start_value)
    return out
示例#11
0
def sharpe_ratio_nb(returns, ann_factor, risk_free):
    """2-dim version of `sharpe_ratio_1d_nb`.

    `risk_free_arr` should be an array of shape `returns.shape[1]`."""
    risk_free_arr = np.asarray(risk_free)
    out = np.empty(returns.shape[1], dtype=np.float_)
    for col in range(returns.shape[1]):
        _risk_free = flex_select_auto_nb(0, col, risk_free_arr, True)
        out[col] = sharpe_ratio_1d_nb(returns[:, col],
                                      ann_factor,
                                      risk_free=_risk_free)
    return out
示例#12
0
def annualized_volatility_nb(returns, ann_factor, levy_alpha):
    """2-dim version of `annualized_volatility_1d_nb`.

    `levy_alpha_arr` should be an array of shape `returns.shape[1]`."""
    levy_alpha_arr = np.asarray(levy_alpha)
    out = np.empty(returns.shape[1], dtype=np.float_)
    for col in range(returns.shape[1]):
        _levy_alpha = flex_select_auto_nb(0, col, levy_alpha_arr, True)
        out[col] = annualized_volatility_1d_nb(returns[:, col],
                                               ann_factor,
                                               levy_alpha=_levy_alpha)
    return out
示例#13
0
def breakout_labels_nb(close, window, pos_th, neg_th, wait=1, flex_2d=True):
    """For each value, return 1 if any value in the next period is greater than the
    positive threshold (in %), -1 if less than the negative threshold, and 0 otherwise.

    First hit wins."""
    out = np.full_like(close, 0, dtype=np.float_)

    for col in range(close.shape[1]):
        for i in range(close.shape[0]):
            _pos_th = abs(flex_select_auto_nb(i, col, pos_th, flex_2d))
            _neg_th = abs(flex_select_auto_nb(i, col, neg_th, flex_2d))

            for j in range(i + wait, min(i + window + wait, close.shape[0])):
                if _pos_th > 0 and close[j, col] >= close[i, col] * (1 + _pos_th):
                    out[i, col] = 1
                    break
                if _neg_th > 0 and close[j, col] <= close[i, col] * (1 - _neg_th):
                    out[i, col] = -1
                    break

    return out
示例#14
0
def sortino_ratio_nb(returns, ann_factor, required_return):
    """2-dim version of `sortino_ratio_1d_nb`.

    `required_return_arr` should be an array of shape `returns.shape[1]`."""
    required_return_arr = np.asarray(required_return)
    out = np.empty(returns.shape[1], dtype=np.float_)
    for col in range(returns.shape[1]):
        _required_return = flex_select_auto_nb(0, col, required_return_arr,
                                               True)
        out[col] = sortino_ratio_1d_nb(returns[:, col],
                                       ann_factor,
                                       required_return=_required_return)
    return out
示例#15
0
def rand_by_prob_choice_nb(col, from_i, to_i, prob, first, temp_idx_arr, flex_2d):
    """`choice_func_nb` to randomly pick values from range `[from_i, to_i)` with probability `prob`.

    `prob` uses flexible indexing."""
    probs = np.asarray(prob)
    j = 0
    for i in range(from_i, to_i):
        if np.random.uniform(0, 1) < flex_select_auto_nb(i, col, probs, flex_2d):  # [0, 1)
            temp_idx_arr[j] = i
            j += 1
            if first:
                break
    return temp_idx_arr[:j]
示例#16
0
文件: nb.py 项目: vroomzel/vectorbt
def rand_by_prob_choice_nb(from_i: int, to_i: int, col: int,
                           prob: tp.MaybeArray[float], pick_first: bool,
                           temp_idx_arr: tp.Array1d,
                           flex_2d: bool) -> tp.Array1d:
    """`choice_func_nb` to randomly pick values from range `[from_i, to_i)` with probability `prob`.

    `prob` uses flexible indexing."""
    probs = np.asarray(prob)
    j = 0
    for i in range(from_i, to_i):
        if np.random.uniform(0, 1) < flex_select_auto_nb(
                probs, i, col, flex_2d):  # [0, 1)
            temp_idx_arr[j] = i
            j += 1
            if pick_first:
                break
    return temp_idx_arr[:j]
示例#17
0
文件: nb.py 项目: jingmouren/vectorbt
def stop_choice_nb(from_i: int,
                   to_i: int,
                   col: int,
                   ts: tp.ArrayLike,
                   stop: tp.MaybeArray[float],
                   trailing: tp.MaybeArray[bool],
                   wait: int,
                   pick_first: bool,
                   temp_idx_arr: tp.Array1d,
                   flex_2d: bool) -> tp.Array1d:
    """`choice_func_nb` that returns the indices of the stop being hit.

    Args:
        from_i (int): Index to start generation from (inclusive).
        to_i (int): Index to run generation to (exclusive).
        col (int): Current column.
        ts (array of float): 2-dim time series array such as price.
        stop (float or array_like): Stop value for stop loss.

            Can be per frame, column, row, or element-wise. Set to `np.nan` to disable.
        trailing (bool or array_like): Whether to use trailing stop.

            Can be per frame, column, row, or element-wise. Set to False to disable.
        wait (int): Number of ticks to wait before placing exits.

            Setting False or 0 may result in two signals at one bar.

            !!! note
                If `wait` is greater than 0, trailing stop won't update at bars that come before `from_i`.
        pick_first (bool): Whether to stop as soon as the first exit signal is found.
        temp_idx_arr (array of int): Empty integer array used to temporarily store indices.
        flex_2d (bool): See `vectorbt.base.reshape_fns.flex_select_auto_nb`."""
    j = 0
    init_i = from_i - wait
    init_ts = flex_select_auto_nb(ts, init_i, col, flex_2d)
    init_stop = flex_select_auto_nb(np.asarray(stop), init_i, col, flex_2d)
    init_trailing = flex_select_auto_nb(np.asarray(trailing), init_i, col, flex_2d)
    max_high = min_low = init_ts

    for i in range(from_i, to_i):
        if not np.isnan(init_stop):
            if init_trailing:
                if init_stop >= 0:
                    # Trailing stop buy
                    curr_stop_price = min_low * (1 + abs(init_stop))
                else:
                    # Trailing stop sell
                    curr_stop_price = max_high * (1 - abs(init_stop))
            else:
                curr_stop_price = init_ts * (1 + init_stop)

        # Check if stop price is within bar
        curr_ts = flex_select_auto_nb(ts, i, col, flex_2d)
        if not np.isnan(init_stop):
            if init_stop >= 0:
                exit_signal = curr_ts >= curr_stop_price
            else:
                exit_signal = curr_ts <= curr_stop_price
            if exit_signal:
                temp_idx_arr[j] = i
                j += 1
                if pick_first:
                    return temp_idx_arr[:1]

        # Keep track of lowest low and highest high if trailing
        if init_trailing:
            if curr_ts < min_low:
                min_low = curr_ts
            elif curr_ts > max_high:
                max_high = curr_ts
    return temp_idx_arr[:j]
示例#18
0
def adv_stop_choice_nb(col, from_i, to_i, open, high, low, close, hit_price_out, stop_type_out,
                       sl_stop, ts_stop, tp_stop, is_open_safe, wait, first, temp_idx_arr, flex_2d):
    """`choice_func_nb` that returns the indices of the stop price being reached.

    Compared to `stop_choice_nb`, takes into account the whole bar, can check for both
    (trailing) stop loss and take profit simultaneously, and tracks hit price and stop type.

    !!! note
        We don't have intra-candle data. If there was a huge price fluctuation in both directions,
        we can't determine whether SL was triggered before TP and vice versa. So some assumptions
        need to be made: 1) trailing stop can only be based on previous close/high, and
        2) we pessimistically assume that SL comes before TS and TP.
    
    Args:
        col (int): Current column.
        from_i (int): Index to start generation from (inclusive).
        to_i (int): Index to run generation to (exclusive).
        open (array_like of float): Entry price such as open or previous close.
        high (array_like of float): High price.
        low (array_like of float): Low price.
        close (array_like of float): Close price.
        hit_price_out (array_like of float): Array where hit price of each exit will be stored.
        stop_type_out (array_like of int): Array where stop type of each exit will be stored.

            0 for stop loss, 1 for take profit.
        sl_stop (float or array_like): Percentage value for stop loss.

            Can be per frame, column, row, or element-wise. Set to 0. to disable.
        ts_stop (bool or array_like): Percentage value for trailing stop.

            Can be per frame, column, row, or element-wise.
        tp_stop (float or array_like): Percentage value for take profit.

            Can be per frame, column, row, or element-wise. Set to 0. to disable.
        is_open_safe (bool): Whether entry price comes right at or before open.

            If True and wait is 0, can use high/low at entry tick. Otherwise uses close.
        wait (bool or int): Number of ticks to wait before placing exits.

            Setting False or 0 may result in two signals at one tick.
        first (bool): Whether to stop as soon as the first exit signal is found.
        temp_idx_arr (array_like of int): Empty integer array used to temporarily store indices.
        flex_2d (bool): See `vectorbt.base.reshape_fns.flex_choose_i_and_col_nb`.
    """
    sl_stops = np.asarray(sl_stop)
    ts_stops = np.asarray(ts_stop)
    tp_stops = np.asarray(tp_stop)

    init_i = from_i - wait
    init_open = flex_select_auto_nb(init_i, col, open, flex_2d)
    init_sl_stop = abs(flex_select_auto_nb(init_i, col, sl_stops, flex_2d))
    init_ts_stop = abs(flex_select_auto_nb(init_i, col, ts_stops, flex_2d))
    init_tp_stop = abs(flex_select_auto_nb(init_i, col, tp_stops, flex_2d))
    max_i = init_i
    max_p = init_open
    j = 0

    for i in range(from_i, to_i):
        # Calculate stop price
        if init_sl_stop > 0:
            curr_sl_stop_price = init_open * (1 - init_sl_stop)
        if init_ts_stop > 0:
            max_ts_stop = abs(flex_select_auto_nb(max_i, col, ts_stops, flex_2d))
            curr_ts_stop_price = max_p * (1 - max_ts_stop)
        if init_tp_stop > 0:
            curr_tp_stop_price = init_open * (1 + init_tp_stop)

        # Check if stop price is within bar
        if i > init_i or is_open_safe:
            # is_open_safe means open is either open or any other price before it
            # so it's safe to use high/low at entry tick
            curr_high = flex_select_auto_nb(i, col, high, flex_2d)
            curr_low = flex_select_auto_nb(i, col, low, flex_2d)
        else:
            # Otherwise, we can only use close price at entry tick
            curr_close = flex_select_auto_nb(i, col, close, flex_2d)
            curr_high = curr_low = curr_close

        exit_signal = False
        if init_sl_stop > 0:
            if curr_low <= curr_sl_stop_price:
                exit_signal = True
                hit_price_out[i, col] = curr_sl_stop_price
                stop_type_out[i, col] = StopType.StopLoss
        if not exit_signal and init_ts_stop > 0:
            if curr_low <= curr_ts_stop_price:
                exit_signal = True
                hit_price_out[i, col] = curr_ts_stop_price
                stop_type_out[i, col] = StopType.TrailStop
        if not exit_signal and init_tp_stop > 0:
            if curr_high >= curr_tp_stop_price:
                exit_signal = True
                hit_price_out[i, col] = curr_tp_stop_price
                stop_type_out[i, col] = StopType.TakeProfit
        if exit_signal:
            temp_idx_arr[j] = i
            j += 1
            if first:
                return temp_idx_arr[:1]

        # Keep track of highest high if trailing
        if init_ts_stop > 0:
            if curr_high > max_p:
                max_i = i
                max_p = curr_high

    return temp_idx_arr[:j]
示例#19
0
def stop_choice_nb(col, from_i, to_i, ts, stop, trailing, wait, first, temp_idx_arr, flex_2d):
    """`choice_func_nb` that returns the indices of the stop being reached.

    Args:
        col (int): Current column.
        from_i (int): Index to start generation from (inclusive).
        to_i (int): Index to run generation to (exclusive).
        ts (array_like): 2-dim time series array such as price.
        stop (float or array_like): Stop value for stop loss.

            Can be per frame, column, row, or element-wise. Set to 0. to disable.
        trailing (bool or array_like): Whether to use trailing stop.

            Can be per frame, column, row, or element-wise.
        wait (bool or int): Number of ticks to wait before placing exits.

            Setting False or 0 may result in two signals at one tick.
        first (bool): Whether to stop as soon as the first exit signal is found.
        temp_idx_arr (int): Empty integer array used to temporarily store indices.
        flex_2d (bool): See `vectorbt.base.reshape_fns.flex_choose_i_and_col_nb`."""
    stops = np.asarray(stop)
    trailings = np.asarray(trailing)

    j = 0
    min_i = max_i = init_i = from_i - wait
    init_ts = flex_select_auto_nb(init_i, col, ts, flex_2d)
    init_stop = flex_select_auto_nb(init_i, col, stops, flex_2d)
    init_trailing = flex_select_auto_nb(init_i, col, trailings, flex_2d)
    max_high = min_low = init_ts

    for i in range(from_i, to_i):
        if init_trailing:
            if init_stop > 0:
                # Trailing stop buy
                last_stop = flex_select_auto_nb(min_i, col, stops, flex_2d)
                curr_stop_price = min_low * (1 + abs(last_stop))
            elif init_stop < 0:
                # Trailing stop sell
                last_stop = flex_select_auto_nb(max_i, col, stops, flex_2d)
                curr_stop_price = max_high * (1 - abs(last_stop))
        else:
            curr_stop_price = init_ts * (1 + init_stop)

        # Check if stop price is within bar
        curr_ts = flex_select_auto_nb(i, col, ts, flex_2d)
        exit_signal = False
        if init_stop > 0:
            exit_signal = curr_ts >= curr_stop_price
        elif init_stop < 0:
            exit_signal = curr_ts <= curr_stop_price
        if exit_signal:
            temp_idx_arr[j] = i
            j += 1
            if first:
                return temp_idx_arr[:1]

        # Keep track of lowest low and highest high if trailing
        if init_trailing:
            if curr_ts < min_low:
                min_i = i
                min_low = curr_ts
            elif curr_ts > max_high:
                max_i = i
                max_high = curr_ts
    return temp_idx_arr[:j]
示例#20
0
def generate_rand_enex_nb(shape, n, entry_wait, exit_wait, seed=None):
    """Pick a number of entries and the same number of exits one after another.

    Respects `entry_wait` and `exit_wait` constraints through a number of tricks.
    Tries to mimic a uniform distribution as much as possible.

    The idea is the following: with constraints, there is some fixed amount of total
    space required between first entry and last exit. Upscale this space in a way that
    distribution of entries and exit is similar to a uniform distribution. This means
    randomizing the position of first entry, last exit, and all signals between them.

    `n` uses flexible indexing.
    Specify `seed` to make output deterministic."""
    if seed is not None:
        np.random.seed(seed)
    entries = np.full(shape, False)
    exits = np.full(shape, False)
    if entry_wait == 0 and exit_wait == 0:
        raise ValueError("entry_wait and exit_wait cannot be both 0")

    if entry_wait == 1 and exit_wait == 1:
        # Basic case
        both = generate_rand_nb(shape, n * 2, seed=None)
        for col in range(both.shape[1]):
            both_idxs = np.flatnonzero(both[:, col])
            entries[both_idxs[0::2], col] = True
            exits[both_idxs[1::2], col] = True
    else:
        ns = np.asarray(n)
        for col in range(shape[1]):
            _n = flex_select_auto_nb(0, col, ns, True)
            if _n == 1:
                entry_idx = np.random.randint(0, shape[0] - exit_wait)
                entries[entry_idx, col] = True
            else:
                # Minimum range between two entries
                min_range = entry_wait + exit_wait

                # Minimum total range between first and last entry
                min_total_range = min_range * (_n - 1)
                if shape[0] < min_total_range + exit_wait + 1:
                    raise ValueError("Cannot take a larger sample than population")

                # We should decide how much space should be allocate before first and after last entry
                # Maximum space outside of min_total_range
                max_free_space = shape[0] - min_total_range - 1

                # If min_total_range is tiny compared to max_free_space, limit it
                # otherwise we would have huge space before first and after last entry
                # Limit it such as distribution of entries mimics uniform
                free_space = min(max_free_space, 3 * shape[0] // (_n + 1))

                # What about last exit? it requires exit_wait space
                free_space -= exit_wait

                # Now we need to distribute free space among three ranges:
                # 1) before first, 2) between first and last added to min_total_range, 3) after last
                # We do 2) such that min_total_range can freely expand to maximum
                # We allocate twice as much for 3) as for 1) because an exit is missing
                rand_floats = uniform_summing_to_one_nb(6)
                chosen_spaces = rescale_float_to_int_nb(rand_floats, (0, free_space), free_space)
                first_idx = chosen_spaces[0]
                last_idx = shape[0] - np.sum(chosen_spaces[-2:]) - exit_wait - 1

                # Selected range between first and last entry
                total_range = last_idx - first_idx

                # Maximum range between two entries within total_range
                max_range = total_range - (_n - 2) * min_range

                # Select random ranges within total_range
                rand_floats = uniform_summing_to_one_nb(_n - 1)
                chosen_ranges = rescale_float_to_int_nb(rand_floats, (min_range, max_range), total_range)

                # Translate them into entries
                entry_idxs = np.empty(_n, dtype=np.int_)
                entry_idxs[0] = first_idx
                entry_idxs[1:] = chosen_ranges
                entry_idxs = np.cumsum(entry_idxs)
                entries[entry_idxs, col] = True

        # Generate exits
        for col in range(shape[1]):
            entry_idxs = np.flatnonzero(entries[:, col])
            for j in range(len(entry_idxs)):
                entry_i = entry_idxs[j] + exit_wait
                if j < len(entry_idxs) - 1:
                    exit_i = entry_idxs[j + 1] - entry_wait
                else:
                    exit_i = entries.shape[0] - 1
                i = np.random.randint(exit_i - entry_i + 1)
                exits[entry_i + i, col] = True
    return entries, exits
示例#21
0
文件: nb.py 项目: jingmouren/vectorbt
def ohlc_stop_choice_nb(from_i: int,
                        to_i: int,
                        col: int,
                        open: tp.ArrayLike,
                        high: tp.ArrayLike,
                        low: tp.ArrayLike,
                        close: tp.ArrayLike,
                        stop_price_out: tp.Array2d,
                        stop_type_out: tp.Array2d,
                        sl_stop: tp.MaybeArray[float],
                        sl_trail: tp.MaybeArray[bool],
                        tp_stop: tp.MaybeArray[float],
                        reverse: tp.MaybeArray[bool],
                        is_open_safe: bool,
                        wait: int,
                        pick_first: bool,
                        temp_idx_arr: tp.Array1d,
                        flex_2d: bool) -> tp.Array1d:
    """`choice_func_nb` that returns the indices of the stop price being hit within OHLC.

    Compared to `stop_choice_nb`, takes into account the whole bar, can check for both
    (trailing) stop loss and take profit simultaneously, and tracks hit price and stop type.

    !!! note
        We don't have intra-candle data. If there was a huge price fluctuation in both directions,
        we can't determine whether SL was triggered before TP and vice versa. So some assumptions
        need to be made: 1) trailing stop can only be based on previous close/high, and
        2) we pessimistically assume that SL comes before TP.
    
    Args:
        col (int): Current column.
        from_i (int): Index to start generation from (inclusive).
        to_i (int): Index to run generation to (exclusive).
        open (array of float): Entry price such as open or previous close.
        high (array of float): High price.
        low (array of float): Low price.
        close (array of float): Close price.
        stop_price_out (array of float): Array where hit price of each exit will be stored.
        stop_type_out (array of int): Array where stop type of each exit will be stored.

            0 for stop loss, 1 for take profit.
        sl_stop (float or array_like): Percentage value for stop loss.

            Can be per frame, column, row, or element-wise. Set to `np.nan` to disable.
        sl_trail (bool or array_like): Whether `sl_stop` is trailing.

            Can be per frame, column, row, or element-wise. Set to False to disable.
        tp_stop (float or array_like): Percentage value for take profit.

            Can be per frame, column, row, or element-wise. Set to `np.nan` to disable.
        reverse (bool or array_like): Whether to do the opposite, i.e.: prices are followed downwards.
        is_open_safe (bool): Whether entry price comes right at or before open.

            If True and wait is 0, can use high/low at entry bar. Otherwise uses only close.
        wait (int): Number of ticks to wait before placing exits.

            Setting False or 0 may result in entry and exit signal at one bar.

            !!! note
                If `wait` is greater than 0, even with `is_open_safe` set to True,
                trailing stop won't update at bars that come before `from_i`.
        pick_first (bool): Whether to stop as soon as the first exit signal is found.
        temp_idx_arr (array of int): Empty integer array used to temporarily store indices.
        flex_2d (bool): See `vectorbt.base.reshape_fns.flex_select_auto_nb`.
    """
    init_i = from_i - wait
    init_open = flex_select_auto_nb(open, init_i, col, flex_2d)
    init_sl_stop = flex_select_auto_nb(np.asarray(sl_stop), init_i, col, flex_2d)
    if init_sl_stop < 0:
        raise ValueError("Stop value must be 0 or greater")
    init_sl_trail = flex_select_auto_nb(np.asarray(sl_trail), init_i, col, flex_2d)
    init_tp_stop = flex_select_auto_nb(np.asarray(tp_stop), init_i, col, flex_2d)
    if init_tp_stop < 0:
        raise ValueError("Stop value must be 0 or greater")
    init_reverse = flex_select_auto_nb(np.asarray(reverse), init_i, col, flex_2d)
    max_p = min_p = init_open
    j = 0

    for i in range(from_i, to_i):
        # Resolve current bar
        _open = flex_select_auto_nb(open, i, col, flex_2d)
        _high = flex_select_auto_nb(high, i, col, flex_2d)
        _low = flex_select_auto_nb(low, i, col, flex_2d)
        _close = flex_select_auto_nb(close, i, col, flex_2d)
        if np.isnan(_open):
            _open = _close
        if np.isnan(_low):
            _low = min(_open, _close)
        if np.isnan(_high):
            _high = max(_open, _close)

        # Calculate stop price
        if not np.isnan(init_sl_stop):
            if init_sl_trail:
                if init_reverse:
                    curr_sl_stop_price = min_p * (1 + init_sl_stop)
                else:
                    curr_sl_stop_price = max_p * (1 - init_sl_stop)
            else:
                if init_reverse:
                    curr_sl_stop_price = init_open * (1 + init_sl_stop)
                else:
                    curr_sl_stop_price = init_open * (1 - init_sl_stop)
        if not np.isnan(init_tp_stop):
            if init_reverse:
                curr_tp_stop_price = init_open * (1 - init_tp_stop)
            else:
                curr_tp_stop_price = init_open * (1 + init_tp_stop)

        # Check if stop price is within bar
        if i > init_i or is_open_safe:
            # is_open_safe means open is either open or any other price before it
            # so it's safe to use high/low at entry bar
            curr_high = _high
            curr_low = _low
        else:
            # Otherwise, we can only use close price at entry bar
            curr_high = curr_low = _close

        exit_signal = False
        if not np.isnan(init_sl_stop):
            if (not init_reverse and curr_low <= curr_sl_stop_price) or \
                    (init_reverse and curr_high >= curr_sl_stop_price):
                exit_signal = True
                stop_price_out[i, col] = curr_sl_stop_price
                if init_sl_trail:
                    stop_type_out[i, col] = StopType.TrailStop
                else:
                    stop_type_out[i, col] = StopType.StopLoss
        if not exit_signal and not np.isnan(init_tp_stop):
            if (not init_reverse and curr_high >= curr_tp_stop_price) or \
                    (init_reverse and curr_low <= curr_tp_stop_price):
                exit_signal = True
                stop_price_out[i, col] = curr_tp_stop_price
                stop_type_out[i, col] = StopType.TakeProfit
        if exit_signal:
            temp_idx_arr[j] = i
            j += 1
            if pick_first:
                return temp_idx_arr[:1]

        # Keep track of highest high if trailing
        if init_sl_trail:
            if curr_low < min_p:
                min_p = curr_low
            if curr_high > max_p:
                max_p = curr_high

    return temp_idx_arr[:j]