diff --git a/portfolio/_service.py b/portfolio/_service.py index 338a1445..3be83e1f 100644 --- a/portfolio/_service.py +++ b/portfolio/_service.py @@ -145,11 +145,11 @@ async def position_risk(self, query: GetPositionRisk): if query.type == PositionSizeType.Kelly: kelly = await self.state.get_kelly(symbol, timeframe, strategy) - return equity * kelly if kelly and kelly > 0 else equity * risk_per_trade + return equity * kelly if kelly > 0 else equity * risk_per_trade if query.type == PositionSizeType.Optimalf: optimalf = await self.state.get_optimalf(symbol, timeframe, strategy) - return equity * optimalf if optimalf else equity * risk_per_trade + return optimalf * equity if optimalf > 0 else equity * risk_per_trade return equity * risk_per_trade diff --git a/position/risk/break_even.py b/position/risk/break_even.py index 9543bb86..bd9c1ce0 100644 --- a/position/risk/break_even.py +++ b/position/risk/break_even.py @@ -23,6 +23,7 @@ def next( ) -> float: ohlcvs = ohlcvs[:] lookback = 14 + factor = 2.0 if len(ohlcvs) < lookback: return stop_loss_price, take_profit_price @@ -40,16 +41,27 @@ def next( high = min(ohlcvs[-lookback:], key=lambda x: abs(x.high - price)).high low = min(ohlcvs[-lookback:], key=lambda x: abs(x.low - price)).low + upper_bb, lower_bb, middle_bb = self._bb(ohlcvs, lookback, factor) + bbw = (upper_bb - lower_bb) / middle_bb + + squeeze = bbw <= np.min(bbw[-lookback:]) + next_stop_loss = stop_loss_price if side == PositionSide.LONG: - next_take_profit = max(entry_price + risk_value, high + tp_threshold) + if squeeze[-1]: + next_take_profit = max(entry_price + risk_value, upper_bb[-1]) + else: + next_take_profit = max(entry_price + risk_value, high + tp_threshold) if curr_dist > dist and price > entry_price: next_stop_loss = max(entry_price - risk_value, low - sl_threshold) elif side == PositionSide.SHORT: - next_take_profit = min(entry_price - risk_value, low - tp_threshold) + if squeeze[-1]: + next_take_profit = min(entry_price - risk_value, lower_bb[-1]) + else: + next_take_profit = min(entry_price - risk_value, low - tp_threshold) if curr_dist > dist and price < entry_price: next_stop_loss = min(entry_price + risk_value, high + sl_threshold) @@ -57,7 +69,7 @@ def next( return next_stop_loss, next_take_profit @staticmethod - def _atr(ohlcvs: List[OHLCV], period: int) -> float: + def _atr(ohlcvs: List[OHLCV], period: int) -> List[float]: highs, lows, closes = ( np.array([ohlcv.high for ohlcv in ohlcvs]), np.array([ohlcv.low for ohlcv in ohlcvs]), @@ -81,3 +93,11 @@ def _atr(ohlcvs: List[OHLCV], period: int) -> float: @staticmethod def _price(ohlcvs: List[OHLCV]) -> float: return (ohlcvs[-1].high + ohlcvs[-1].low + ohlcvs[-1].close) / 3.0 + + @staticmethod + def _bb(ohlcvs: List[OHLCV], period: int, factor: float) -> Tuple[List[float], List[float], List[float]]: + closes = np.array([ohlcv.close for ohlcv in ohlcvs]) + rolling_mean = np.convolve(closes, np.ones(period) / period, mode='valid') + rolling_std = factor * np.std([closes[i:i+period] for i in range(len(closes) - period + 1)], axis=1) + + return rolling_mean + rolling_std, rolling_mean - rolling_std, rolling_mean \ No newline at end of file diff --git a/position/size/optimal_f.py b/position/size/optimal_f.py index 4c16bedb..d8f8f990 100644 --- a/position/size/optimal_f.py +++ b/position/size/optimal_f.py @@ -20,8 +20,6 @@ async def calculate( GetPositionRisk(signal, PositionSizeType.Optimalf) ) - risk_amount = await self.query(GetPositionRisk(signal, PositionSizeType.Fixed)) - if stop_loss_price is not None and entry_price is not None: price_difference = abs(entry_price - stop_loss_price) else: @@ -34,4 +32,6 @@ async def calculate( position_size = risk_amount / price_difference + print(f"Risk {risk_amount}, Size {position_size}") + return position_size diff --git a/quant.py b/quant.py index 5e823dc1..f904b934 100644 --- a/quant.py +++ b/quant.py @@ -19,7 +19,7 @@ from portfolio import Portfolio from position import PositionActorFactory, PositionFactory from position.risk.break_even import PositionRiskBreakEvenStrategy -from position.size.optimal_f import PositionOptimalFSizeStrategy +from position.size.fixed import PositionFixedSizeStrategy from position.take_profit.risk_reward import PositionRiskRewardTakeProfitStrategy from risk import RiskActorFactory from service import EnvironmentSecretService, SignalService, WasmFileService @@ -68,7 +68,7 @@ async def main(): SmartRouter(exchange_factory, config_service) position_factory = PositionFactory( - PositionOptimalFSizeStrategy(), + PositionFixedSizeStrategy(), PositionRiskBreakEvenStrategy(config_service), PositionRiskRewardTakeProfitStrategy(config_service), ) diff --git a/strategy/generator/baseline/ma.py b/strategy/generator/baseline/ma.py index 631f4732..6526c25e 100644 --- a/strategy/generator/baseline/ma.py +++ b/strategy/generator/baseline/ma.py @@ -14,4 +14,4 @@ class MaBaseLine(BaseLine): type: BaseLineType = BaseLineType.Ma ma: Parameter = CategoricalParameter(MovingAverageType) - period: Parameter = StaticParameter(24.0) + period: Parameter = StaticParameter(14.0) diff --git a/strategy/generator/signal/ma/ma_cross.py b/strategy/generator/signal/ma/ma_cross.py index 61e25291..5ad8aae9 100644 --- a/strategy/generator/signal/ma/ma_cross.py +++ b/strategy/generator/signal/ma/ma_cross.py @@ -10,4 +10,4 @@ class MaCrossSignal(Signal): type: SignalType = SignalType.MaCross ma: Parameter = CategoricalParameter(MovingAverageType) - period: Parameter = RandomParameter(150.0, 200.0, 10.0) + period: Parameter = RandomParameter(100.0, 150.0, 10.0)