Repository: hummingbot/hummingbot
Pull request: Feat  / add position management for perpetual strategy
**Before submitting this PR, please make sure**:

- [x] Your code builds clean without any errors or warnings
- [x] You are using approved title ("feat/", "fix/", "docs/", "refactor/")

**After creating this PR, please make sure:**

- [x] You link the related GitHub issue or ticket

**A description of the changes proposed in the pull request**:



Problem statement:
[Feature] Derivatives position profit taking feature
**Feature Suggestion**
A feature to be able to define a take-profit % value for derivatives would be nice.

**Impact**
// A succinct description of **why you want the _desired behavior_** specified above.

This could make market making more profitable on perpetual contracts. Currently, there is no way of locking in a profitable position and while the positions do go into good profitable levels, they often get closed out at a loss again as there are no opposite closing orders during trends.

I would like to be able to set a profit level at which a position should be closed via configurable order type [market, limit, stop or trailing-stop]. I know @vic-en had already started work on position management, so would be nice to finish the implementation.

Also, Hedge/Non-Hedge would need a slightly different approach.

[Feature] Implement position trailing stop feature in Perpetual Market Making
**Feature Suggestion**
Parameters: 
`activation_spread(%)` - relative distance from the mid-price which determines when trailing stop would begin. When set to zero or equals either bid or ask spread, trailing stop begins immediately.
`callback_rate(%)` - relative distance from the maximum price(for long positions) and minimum price(for short positions) at which positions will be closed.

For accuracy, trailing stop would keep trailing the top order of the orderbook(i.e ask side for long position and bid side for short positions) and close position using `limit order`.

Hints from issue discussion:

Commit message: Merge branch 'feat/position_management_for_perpetual_strategy' of https://github.com/CoinAlpha/hummingbot into feat/position_management_for_perpetual_strategy

Patch to review:
diff --git a/hummingbot/client/command/create_command.py b/hummingbot/client/command/create_command.py
index 012d1440ef0..f769751d2d5 100644
--- a/hummingbot/client/command/create_command.py
+++ b/hummingbot/client/command/create_command.py
@@ -58,7 +58,7 @@ async def prompt_for_configuration(self,  # type: HummingbotApplication
             else:
                 config.value = None
         for config in config_map.values():
-            if config.prompt_on_new:
+            if config.prompt_on_new and config.required:
                 if not self.app.to_stop_config:
                     await self.prompt_a_config(config)
                 else:
diff --git a/hummingbot/connector/derivative/binance_perpetual/binance_perpetual_api_order_book_data_source.py b/hummingbot/connector/derivative/binance_perpetual/binance_perpetual_api_order_book_data_source.py
index 09d50deb86a..b6e54ed7209 100644
--- a/hummingbot/connector/derivative/binance_perpetual/binance_perpetual_api_order_book_data_source.py
+++ b/hummingbot/connector/derivative/binance_perpetual/binance_perpetual_api_order_book_data_source.py
@@ -106,11 +106,14 @@ async def fetch_trading_pairs(domain=None) -> List[str]:
                         raw_trading_pairs = [d["symbol"] for d in data["symbols"] if d["status"] == "TRADING"]
                         trading_pair_list: List[str] = []
                         for raw_trading_pair in raw_trading_pairs:
-                            trading_pair = convert_from_exchange_trading_pair(raw_trading_pair)
-                            if trading_pair is not None:
-                                trading_pair_list.append(trading_pair)
-                            else:
-                                continue
+                            try:
+                                trading_pair = convert_from_exchange_trading_pair(raw_trading_pair)
+                                if trading_pair is not None:
+                                    trading_pair_list.append(trading_pair)
+                                else:
+                                    continue
+                            except Exception:
+                                pass
                         return trading_pair_list
         except Exception:
             pass
diff --git a/hummingbot/connector/derivative/binance_perpetual/binance_perpetual_derivative.py b/hummingbot/connector/derivative/binance_perpetual/binance_perpetual_derivative.py
index ae090977c8c..dbe8542ca4a 100644
--- a/hummingbot/connector/derivative/binance_perpetual/binance_perpetual_derivative.py
+++ b/hummingbot/connector/derivative/binance_perpetual/binance_perpetual_derivative.py
@@ -38,7 +38,7 @@
     BuyOrderCreatedEvent,
     SellOrderCreatedEvent,
     OrderFilledEvent,
-    SellOrderCompletedEvent, PositionSide, PositionMode)
+    SellOrderCompletedEvent, PositionSide, PositionMode, PositionAction)
 from hummingbot.core.utils.async_utils import safe_ensure_future, safe_gather
 from hummingbot.core.utils.asyncio_throttle import Throttler
 from hummingbot.logger import HummingbotLogger
@@ -219,14 +219,15 @@ async def create_order(self,
                            trading_pair: str,
                            amount: Decimal,
                            order_type: OrderType,
+                           position_action: PositionAction,
                            price: Optional[Decimal] = Decimal("NaN")):
 
         trading_rule: TradingRule = self._trading_rules[trading_pair]
-        if order_type == OrderType.LIMIT_MAKER:
-            raise ValueError("Binance Perpetuals does not support the Limit Maker order type.")
+        if position_action not in [PositionAction.OPEN, PositionAction.CLOSE]:
+            raise ValueError("Specify either OPEN_POSITION or CLOSE_POSITION position_action.")
 
         amount = self.quantize_order_amount(trading_pair, amount)
-        price = Decimal("NaN") if order_type == OrderType.MARKET else self.quantize_order_price(trading_pair, price)
+        price = self.quantize_order_price(trading_pair, price)
 
         if amount < trading_rule.min_order_size:
             raise ValueError(f"Buy order amount {amount} is lower than the minimum order size "
@@ -235,17 +236,19 @@ async def create_order(self,
         order_result = None
         api_params = {"symbol": convert_to_exchange_trading_pair(trading_pair),
                       "side": "BUY" if trade_type is TradeType.BUY else "SELL",
-                      "type": order_type.name.upper(),
+                      "type": "LIMIT" if order_type is OrderType.LIMIT else "MARKET",
                       "quantity": f"{amount}",
                       "newClientOrderId": order_id
                       }
-        if order_type != OrderType.MARKET:
-            api_params["price"] = f"{price}"
         if order_type == OrderType.LIMIT:
+            api_params["price"] = f"{price}"
             api_params["timeInForce"] = "GTC"
 
         if self._position_mode == PositionMode.HEDGE:
-            api_params["positionSide"] = "LONG" if trade_type is TradeType.BUY else "SHORT"
+            if position_action == PositionAction.OPEN:
+                api_params["positionSide"] = "LONG" if trade_type is TradeType.BUY else "SHORT"
+            else:
+                api_params["positionSide"] = "SHORT" if trade_type is TradeType.BUY else "LONG"
 
         self.start_tracking_order(order_id, "", trading_pair, trade_type, price, amount, order_type)
 
@@ -291,15 +294,16 @@ async def execute_buy(self,
                           trading_pair: str,
                           amount: Decimal,
                           order_type: OrderType,
+                          position_action: PositionAction,
                           price: Optional[Decimal] = s_decimal_NaN):
-        return await self.create_order(TradeType.BUY, order_id, trading_pair, amount, order_type, price)
+        return await self.create_order(TradeType.BUY, order_id, trading_pair, amount, order_type, position_action, price)
 
     def buy(self, trading_pair: str, amount: object, order_type: object = OrderType.MARKET,
             price: object = s_decimal_NaN, **kwargs) -> str:
 
         t_pair: str = trading_pair
         order_id: str = get_client_order_id("sell", t_pair)
-        safe_ensure_future(self.execute_buy(order_id, trading_pair, amount, order_type, price))
+        safe_ensure_future(self.execute_buy(order_id, trading_pair, amount, order_type, kwargs["position_action"], price))
         return order_id
 
     async def execute_sell(self,
@@ -307,15 +311,16 @@ async def execute_sell(self,
                            trading_pair: str,
                            amount: Decimal,
                            order_type: OrderType,
+                           position_action: PositionAction,
                            price: Optional[Decimal] = s_decimal_NaN):
-        return await self.create_order(TradeType.SELL, order_id, trading_pair, amount, order_type, price)
+        return await self.create_order(TradeType.SELL, order_id, trading_pair, amount, order_type, position_action, price)
 
     def sell(self, trading_pair: str, amount: object, order_type: object = OrderType.MARKET,
              price: object = s_decimal_NaN, **kwargs) -> str:
 
         t_pair: str = trading_pair
         order_id: str = get_client_order_id("sell", t_pair)
-        safe_ensure_future(self.execute_sell(order_id, trading_pair, amount, order_type, price))
+        safe_ensure_future(self.execute_sell(order_id, trading_pair, amount, order_type, kwargs["position_action"], price))
         return order_id
 
     async def cancel_all(self, timeout_seconds: float):
@@ -513,7 +518,7 @@ async def _user_stream_event_listener(self):
                             else:
                                 event_tag = self.MARKET_SELL_ORDER_COMPLETED_EVENT_TAG
                                 event_class = SellOrderCompletedEvent
-                            self.logger().info(f"The market {trade_type} order {client_order_id} has completed "
+                            self.logger().info(f"The {tracked_order.order_type.name.lower()} {trade_type} order {client_order_id} has completed "
                                                f"according to websocket delta.")
                             self.trigger_event(event_tag,
                                                event_class(self.current_timestamp,
@@ -533,7 +538,7 @@ async def _user_stream_event_listener(self):
                                                        OrderCancelledEvent(self.current_timestamp,
                                                                            tracked_order.client_order_id))
                                 else:
-                                    self.logger().info(f"The market order {tracked_order.client_order_id} has failed "
+                                    self.logger().info(f"The {tracked_order.order_type.name.lower()} order {tracked_order.client_order_id} has failed "
                                                        f"according to websocket delta.")
                                     self.trigger_event(self.MARKET_ORDER_FAILURE_EVENT_TAG,
                                                        MarketOrderFailureEvent(self.current_timestamp,
@@ -716,9 +721,9 @@ async def _update_positions(self):
             position_side = PositionSide[position.get("positionSide")]
             unrealized_pnl = Decimal(position.get("unRealizedProfit"))
             entry_price = Decimal(position.get("entryPrice"))
-            amount = abs(Decimal(position.get("positionAmt")))
+            amount = Decimal(position.get("positionAmt"))
             leverage = Decimal(position.get("leverage"))
-            if amount > 0:
+            if amount != 0:
                 self._account_positions[trading_pair + position_side.name] = Position(
                     trading_pair=convert_from_exchange_trading_pair(trading_pair),
                     position_side=position_side,
@@ -840,7 +845,7 @@ async def _update_order_status(self):
 
                             event_tag = self.MARKET_SELL_ORDER_COMPLETED_EVENT_TAG
                             event_class = SellOrderCompletedEvent
-                        self.logger().info(f"The market {tracked_order.trade_type.name} order {client_order_id} has "
+                        self.logger().info(f"The {order_type.name.lower()} {tracked_order.trade_type.name.lower()} order {client_order_id} has "
                                            f"completed according to order status API.")
                         self.trigger_event(event_tag,
                                            event_class(self.current_timestamp,
@@ -859,7 +864,7 @@ async def _update_order_status(self):
                                                OrderCancelledEvent(self.current_timestamp,
                                                                    client_order_id))
                         else:
-                            self.logger().info(f"The market order {client_order_id} has failed according to "
+                            self.logger().info(f"The {order_type.name.lower()} order {client_order_id} has failed according to "
                                                f"order status API.")
                             self.trigger_event(self.MARKET_ORDER_FAILURE_EVENT_TAG,
                                                MarketOrderFailureEvent(self.current_timestamp,
diff --git a/hummingbot/core/event/events.py b/hummingbot/core/event/events.py
index 3289a07cf85..03092ba181f 100644
--- a/hummingbot/core/event/events.py
+++ b/hummingbot/core/event/events.py
@@ -71,6 +71,11 @@ def is_limit_type(self):
         return self in (OrderType.LIMIT, OrderType.LIMIT_MAKER)
 
 
+class PositionAction(Enum):
+    OPEN = "OPEN"
+    CLOSE = "CLOSE"
+
+
 # For Derivatives Exchanges
 class PositionSide(Enum):
     LONG = "LONG"
diff --git a/hummingbot/strategy/perpetual_market_making/perpetual_market_making.pxd b/hummingbot/strategy/perpetual_market_making/perpetual_market_making.pxd
index d54d888911f..50cbbc20884 100644
--- a/hummingbot/strategy/perpetual_market_making/perpetual_market_making.pxd
+++ b/hummingbot/strategy/perpetual_market_making/perpetual_market_making.pxd
@@ -13,6 +13,12 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
         object _ask_spread
         object _minimum_spread
         object _order_amount
+        str _position_management
+        object _long_profit_taking_spread
+        object _short_profit_taking_spread
+        object _ts_activation_spread
+        object _ts_callback_rate
+        object _close_position_order_type
         int _order_levels
         int _buy_levels
         int _sell_levels
@@ -49,8 +55,12 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
         double _status_report_interval
         int64_t _logging_options
         object _last_own_trade_price
-    cdef c_manage_positions(self)
-    cdef create_ts_order(self, bint side, object price, object size, object order_type)
+        object _ts_peak_bid_price
+        object _ts_peak_ask_price
+        list _ts_exit_orders
+    cdef c_manage_positions(self, list session_positions)
+    cdef c_profit_taking_feature(self, object mode, list active_positions)
+    cdef c_trailing_stop_feature(self, object mode, list active_positions)
     cdef c_apply_initial_settings(self, str trading_pair, object position, int64_t leverage)
     cdef object c_get_mid_price(self)
     cdef object c_create_base_proposal(self)
@@ -68,5 +78,5 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
     cdef c_cancel_hanging_orders(self)
     cdef c_cancel_orders_below_min_spread(self)
     cdef bint c_to_create_orders(self, object proposal)
-    cdef c_execute_orders_proposal(self, object proposal)
+    cdef c_execute_orders_proposal(self, object proposal, object position_action)
     cdef set_timers(self)
diff --git a/hummingbot/strategy/perpetual_market_making/perpetual_market_making.pyx b/hummingbot/strategy/perpetual_market_making/perpetual_market_making.pyx
index 6104a510b02..a0f0faad289 100644
--- a/hummingbot/strategy/perpetual_market_making/perpetual_market_making.pyx
+++ b/hummingbot/strategy/perpetual_market_making/perpetual_market_making.pyx
@@ -13,7 +13,13 @@ from math import (
 )
 import time
 from hummingbot.core.clock cimport Clock
-from hummingbot.core.event.events import TradeType, PriceType, PositionSide, PositionMode
+from hummingbot.core.event.events import (
+    TradeType,
+    PriceType,
+    PositionAction,
+    PositionSide,
+    PositionMode
+)
 from hummingbot.core.data_type.limit_order cimport LimitOrder
 from hummingbot.core.data_type.limit_order import LimitOrder
 from hummingbot.core.network_iterator import NetworkStatus
@@ -61,10 +67,16 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
     def __init__(self,
                  market_info: MarketTradingPairTuple,
                  leverage: int,
-                 position_mode: bool,
+                 position_mode: str,
                  bid_spread: Decimal,
                  ask_spread: Decimal,
                  order_amount: Decimal,
+                 position_management: str,
+                 long_profit_taking_spread: Decimal,
+                 short_profit_taking_spread: Decimal,
+                 ts_activation_spread: Decimal,
+                 ts_callback_rate: Decimal,
+                 close_position_order_type: str,
                  order_levels: int = 1,
                  order_level_spread: Decimal = s_decimal_zero,
                  order_level_amount: Decimal = s_decimal_zero,
@@ -97,11 +109,17 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
         self._sb_order_tracker = PerpetualMarketMakingOrderTracker()
         self._market_info = market_info
         self._leverage = leverage
-        self._position_mode = PositionMode.HEDGE if position_mode else PositionMode.ONEWAY
+        self._position_mode = PositionMode.HEDGE if position_mode == "Hedge" else PositionMode.ONEWAY
         self._bid_spread = bid_spread
         self._ask_spread = ask_spread
         self._minimum_spread = minimum_spread
         self._order_amount = order_amount
+        self._position_management = position_management
+        self._long_profit_taking_spread = long_profit_taking_spread
+        self._short_profit_taking_spread = short_profit_taking_spread
+        self._ts_activation_spread = ts_activation_spread
+        self._ts_callback_rate = ts_callback_rate
+        self._close_position_order_type = OrderType.MARKET if close_position_order_type == "MARKET" else OrderType.LIMIT
         self._order_levels = order_levels
         self._buy_levels = order_levels
         self._sell_levels = order_levels
@@ -128,9 +146,6 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
 
         self._cancel_timestamp = 0
         self._create_timestamp = 0
-        self._limit_order_type = self._market_info.market.get_maker_order_type()
-        if take_if_crossed:
-            self._limit_order_type = OrderType.LIMIT
         self._all_markets_ready = False
         self._filled_buys_balance = 0
         self._filled_sells_balance = 0
@@ -140,6 +155,9 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
         self._last_timestamp = 0
         self._status_report_interval = status_report_interval
         self._last_own_trade_price = Decimal('nan')
+        self._ts_peak_bid_price = Decimal('0')
+        self._ts_peak_ask_price = Decimal('0')
+        self._ts_exit_orders = []
 
         self.c_add_markets([market_info.market])
 
@@ -368,11 +386,6 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
         orders = [o for o in self.active_orders if o.client_order_id not in self._hanging_order_ids]
         return orders
 
-    @property
-    def active_position_orders(self) -> List[LimitOrder]:
-        # assume active orders are position exit orders for simplicity
-        return self.active_orders
-
     @property
     def logging_options(self) -> int:
         return self._logging_options
@@ -525,8 +538,8 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
 
     # The following exposed Python functions are meant for unit tests
     # ---------------------------------------------------------------
-    def execute_orders_proposal(self, proposal: Proposal):
-        return self.c_execute_orders_proposal(proposal)
+    def execute_orders_proposal(self, proposal: Proposal, position_action: PositionAction):
+        return self.c_execute_orders_proposal(proposal, position_action)
 
     def cancel_order(self, order_id: str):
         return self.c_cancel_order(self._market_info, order_id)
@@ -547,6 +560,8 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
     cdef c_tick(self, double timestamp):
         StrategyBase.c_tick(self, timestamp)
         cdef:
+            ExchangeBase market = self._market_info.market
+            list session_positions = [s for s in self.active_positions.values() if s.trading_pair == self.trading_pair]
             int64_t current_tick = <int64_t>(timestamp // self._status_report_interval)
             int64_t last_tick = <int64_t>(self._last_timestamp // self._status_report_interval)
             bint should_report_warnings = ((current_tick > last_tick) and
@@ -558,7 +573,7 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
                 if self._asset_price_delegate is not None and self._all_markets_ready:
                     self._all_markets_ready = self._asset_price_delegate.ready
                 if not self._all_markets_ready:
-                    # Markets not ready yet. Don't do anything.
+                    # M({self.trading_pair}) Maker sell order {order_id}arkets not ready yet. Don't do anything.
                     if should_report_warnings:
                         self.logger().warning(f"Markets are not ready. No market making trades are permitted.")
                     return
@@ -568,78 +583,188 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
                     self.logger().warning(f"WARNING: Some markets are not connected or are down at the moment. Market "
                                           f"making may be dangerous when markets or networks are unstable.")
 
-            # if len(self.active_positions) == 0:
-            proposal = None
-            asset_mid_price = Decimal("0")
-            # asset_mid_price = self.c_set_mid_price(market_info)
-            if self._create_timestamp <= self._current_timestamp:
-                # 1. Create base order proposals
-                proposal =self.c_create_base_proposal()
-                # 2. Apply functions that limit numbers of buys and sells proposal
-                self.c_apply_order_levels_modifiers(proposal)
-                # 3. Apply functions that modify orders price
-                self.c_apply_order_price_modifiers(proposal)
-                # 4. Apply budget constraint, i.e. can't buy/sell more than what you have.
-                self.c_apply_budget_constraint(proposal)
-
-                if not self._take_if_crossed:
-                    self.c_filter_out_takers(proposal)
-            self.c_cancel_active_orders(proposal)
-            self.c_cancel_hanging_orders()
-            self.c_cancel_orders_below_min_spread()
-            if self.c_to_create_orders(proposal):
-                self.c_execute_orders_proposal(proposal)
-            """else:
-                self.c_manage_positions()"""
+            if len(session_positions) == 0:
+                proposal = None
+                asset_mid_price = Decimal("0")
+                # asset_mid_price = self.c_set_mid_price(market_info)
+                if self._create_timestamp <= self._current_timestamp:
+                    # 1. Create base order proposals
+                    proposal =self.c_create_base_proposal()
+                    # 2. Apply functions that limit numbers of buys and sells proposal
+                    self.c_apply_order_levels_modifiers(proposal)
+                    # 3. Apply functions that modify orders price
+                    self.c_apply_order_price_modifiers(proposal)
+                    # 4. Apply budget constraint, i.e. can't buy/sell more than what you have.
+                    self.c_apply_budget_constraint(proposal)
+
+                    if not self._take_if_crossed:
+                        self.c_filter_out_takers(proposal)
+                self.c_cancel_active_orders(proposal)
+                self.c_cancel_hanging_orders()
+                self.c_cancel_orders_below_min_spread()
+                if self.c_to_create_orders(proposal):
+                    self.c_execute_orders_proposal(proposal, PositionAction.OPEN)
+                # Reset peak ask and bid prices
+                self._ts_peak_ask_price = market.get_price(self.trading_pair, False)
+                self._ts_peak_bid_price = market.get_price(self.trading_pair, True)
+            else:
+                self.c_manage_positions(session_positions)
         finally:
             self._last_timestamp = timestamp
 
-    cdef c_manage_positions(self):
-        order_type = OrderType.TRAILING_STOP
+    cdef c_manage_positions(self, list session_positions):
+        cdef:
+            object mode = self._position_mode
 
-        for position in self.active_positions.values():
-            exit_orders = [o for o in self.active_position_orders if o.trading_pair == position.trading_pair]
+        if self._position_management == "Profit_taking":
+            proposals = self.c_profit_taking_feature(mode, session_positions)
+        else:
+            proposals = self.c_trailing_stop_feature(mode, session_positions)
+        if proposals is not None:
+            self.c_execute_orders_proposal(proposals, PositionAction.CLOSE)
 
-            if len(exit_orders) == 0:
-                self.logger().info(f"Creating trailing stop order to close position in {position.trading_pair}.")
+    cdef c_profit_taking_feature(self, object mode, list active_positions):
+        cdef:
+            ExchangeBase market = self._market_info.market
+            list active_orders = self.active_orders
+            list buys = []
+            list sells = []
 
-                side = True if position.amount < 0 else False
-                size = abs(position.amount)
-                price = self._ts_callback_rate  # use price for trailing stop callback rate
-                return self.create_ts_order(side, price, size, order_type)
+        if mode == PositionMode.ONEWAY:
+            # in one-way mode, only one active position is expected per time
+            if len(active_positions) > 1:
+                self.logger().error(f"Kindly ensure you do not interract with the exchange through other platforms and restart this strategy.")
             else:
-                # check if the all exit orders can exit position accurately, else create more orders
-
-                total_amount = Decimal("0")
-                expected_amount = abs(position.amount)
-
-                for exit_order in exit_orders:
-                    total_amount += exit_order.quantity
+                # Cancel open order that could potentially close position before reaching take_profit_limit
+                unwanted_exit_orders = [o for o in active_orders if o.client_order_id not in self._ts_exit_orders]
+                for order in unwanted_exit_orders:
+                    if active_positions[0].amount < 0 and order.is_buy:
+                        self.c_cancel_order(self._market_info, order.client_order_id)
+                        self.logger().info(f"Cancelled buy order {order.client_order_id} in favour of take profit order.")
+                    elif active_positions[0].amount > 0 and not order.is_buy:
+                        self.c_cancel_order(self._market_info, order.client_order_id)
+                        self.logger().info(f"Cancelled sell order {order.client_order_id} in favour of take profit order.")
+
+        for position in active_positions:
+            # check if there is an active order to take profit, and create if none exists
+            profit_spread = self._long_profit_taking_spread if position.amount < 0 else self._short_profit_taking_spread
+            take_profit_price = position.entry_price * (Decimal("1") + profit_spread) if position.amount > 0 \
+                else position.entry_price * (Decimal("1") - profit_spread)
+            price = market.c_quantize_order_price(self.trading_pair, take_profit_price)
+            exit_order_exists = [o for o in active_orders if o.price == price]
+            if len(exit_order_exists) == 0:
+                size = market.c_quantize_order_amount(self.trading_pair, abs(position.amount))
+                if size > 0 and price > 0:
+                    if position.amount < 0:
+                        buys.append(PriceSize(price, size))
+                    else:
+                        sells.append(PriceSize(price, size))
+        return Proposal(buys, sells)
 
-                if total_amount < expected_amount:
-                    self.logger().info(f"Creating extra trailing stop order to close position in {position.trading_pair}.")
+    cdef c_trailing_stop_feature(self, object mode, list active_positions):
+        cdef:
+            ExchangeBase market = self._market_info.market
+            list active_orders = self.active_orders
+            list buys = []
+            list sells = []
 
-                    side = True if position.amount < 0 else False
-                    size = expected_amount - total_amount
-                    price = self._ts_callback_rate  # use price for trailing stop callback rate
-                    return self.create_ts_order(side, price, size, order_type)
+        # Notes:
+        # -The top bid is used for trailing short position and the top ask for long positions
+        # -Long positions are closed immediately when the current price is below the entry price
+        # -Short positions are closed immediately when the current price is above the entry price
+        # -Trailing wouldn't begin until current price hits the price set by ts_activation_spread
 
-    cdef create_ts_order(self, bint side, object price, object size, object order_type):
-        if side is True:
-            order_id = self.c_buy_with_specific_market(
-                self._market_info,
-                size,
-                order_type=order_type,
-                price=price
-            )
-        else:
-            order_id = self.c_sell_with_specific_market(
-                self._market_info,
-                size,
-                order_type=order_type,
-                price=price
-            )
-        return order_id
+        if mode == PositionMode.ONEWAY:
+            # in one-way mode, only one active position is expected per time
+            if len(active_positions) > 1:
+                self.logger().info(f"Kindly ensure you do not interract with the exchange through other platforms and restart this strategy.")
+            else:
+                # Cancel open order that could potentially close position and affect trailing stop functionality
+                unwanted_exit_orders = [o for o in active_orders if o.client_order_id not in self._ts_exit_orders]
+                for order in unwanted_exit_orders:
+                    if active_positions[0].amount < 0 and order.is_buy:
+                        self.c_cancel_order(self._market_info, order.client_order_id)
+                        self.logger().info(f"Cancelled buy order {order.client_order_id} in favour of trailing stop.")
+                    elif active_positions[0].amount > 0 and not order.is_buy:
+                        self.c_cancel_order(self._market_info, order.client_order_id)
+                        self.logger().info(f"Cancelled sell order {order.client_order_id} in favour of trailing stop.")
+
+        for position in active_positions:
+            if position.amount == Decimal("0"):
+                continue
+            if position.amount > 0:  # this is a long position
+                top_ask = market.get_price(self.trading_pair, False)
+                if top_ask < position.entry_price:
+                    exit_price = market.get_price_for_volume(self.trading_pair, False,
+                                                             abs(position.amount)).result_price
+                    price = market.c_quantize_order_price(self.trading_pair, exit_price)
+
+                    # Do some checks to prevent duplicating orders to close positions
+                    exit_order_exists = [o for o in active_orders if o.client_order_id in self._ts_exit_orders]
+                    create_order = True
+                    self._ts_exit_orders = [] if len(exit_order_exists) == 0 else self._ts_exit_orders
+                    for order in exit_order_exists:
+                        if not order.is_buy:
+                            create_order = False
+                    if create_order is True:
+                        self.logger().info(f"Closing long position immediately to stop-loss.")
+                        sells.append(PriceSize(price, abs(position.amount)))
+                elif max(top_ask, self._ts_peak_ask_price) >= (position.entry_price * (Decimal("1") + self._ts_activation_spread)):
+                    if top_ask > self._ts_peak_ask_price or self._ts_peak_ask_price == Decimal("0"):
+                        self._ts_peak_ask_price = top_ask
+                    elif top_ask <= (self._ts_peak_ask_price * (Decimal("1") - self._ts_callback_rate)):
+                        exit_price = market.get_price_for_volume(self.trading_pair, False,
+                                                                 abs(position.amount)).result_price
+                        price = market.c_quantize_order_price(self.trading_pair, exit_price)
+
+                        # Do some checks to prevent duplicating orders to close positions
+                        exit_order_exists = [o for o in active_orders if o.client_order_id in self._ts_exit_orders]
+                        create_order = True
+                        self._ts_exit_orders = [] if len(exit_order_exists) == 0 else self._ts_exit_orders
+                        for order in exit_order_exists:
+                            if not order.is_buy:
+                                create_order = False
+                        if create_order is True:
+                            sells.append(PriceSize(price, abs(position.amount)))
+                            self.logger().info(f"Trailing stop will Close long position immediately at {price}{self.quote_asset} due deviation "
+                                               f"from {self._ts_peak_ask_price} {self.quote_asset} trailing maximum price to secure profit.")
+            else:
+                top_bid = market.get_price(self.trading_pair, True)
+                if top_bid > position.entry_price:
+                    exit_price = market.get_price_for_volume(self.trading_pair, True,
+                                                             abs(position.amount)).result_price
+                    price = market.c_quantize_order_price(self.trading_pair, exit_price)
+
+                    # Do some checks to prevent duplicating orders to close positions
+                    exit_order_exists = [o for o in active_orders if o.client_order_id in self._ts_exit_orders]
+                    create_order = True
+                    self._ts_exit_orders = [] if len(exit_order_exists) == 0 else self._ts_exit_orders
+                    for order in exit_order_exists:
+                        if order.is_buy:
+                            create_order = False
+                    if create_order is True:
+                        buys.append(PriceSize(price, abs(position.amount)))
+                        self.logger().info(f"Closing short position immediately to stop-loss.")
+                elif min(top_bid, self._ts_peak_bid_price) <= (position.entry_price * (Decimal("1") - self._ts_activation_spread)):
+                    if top_bid < self._ts_peak_bid_price or self._ts_peak_ask_price == Decimal("0"):
+                        self._ts_peak_bid_price = top_bid
+                    elif top_bid >= (self._ts_peak_bid_price * (Decimal("1") + self._ts_callback_rate)):
+                        exit_price = market.get_price_for_volume(self.trading_pair, True,
+                                                                 abs(position.amount)).result_price
+                        price = market.c_quantize_order_price(self.trading_pair, exit_price)
+
+                        # Do some checks to prevent duplicating orders to close positions
+                        exit_order_exists = [o for o in active_orders if o.client_order_id in self._ts_exit_orders]
+                        create_order = True
+                        self._ts_exit_orders = [] if len(exit_order_exists) == 0 else self._ts_exit_orders
+                        for order in exit_order_exists:
+                            if order.is_buy:
+                                create_order = False
+                        if create_order is True:
+                            buys.append(PriceSize(price, abs(position.amount)))
+                            self.logger().info(f"Trailing stop will close short position immediately at {price}{self.quote_asset} due deviation "
+                                               f"from {self._ts_peak_bid_price}{self.quote_asset} trailing minimum price to secure profit.")
+            return Proposal(buys, sells)
 
     cdef object c_create_base_proposal(self):
         cdef:
@@ -837,12 +962,12 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
             ExchangeBase market = self._market_info.market
         for buy in proposal.buys:
             fee = market.c_get_fee(self.base_asset, self.quote_asset,
-                                   self._limit_order_type, TradeType.BUY, buy.size, buy.price)
+                                   OrderType.LIMIT, TradeType.BUY, buy.size, buy.price)
             price = buy.price * (Decimal(1) - fee.percent)
             buy.price = market.c_quantize_order_price(self.trading_pair, price)
         for sell in proposal.sells:
             fee = market.c_get_fee(self.base_asset, self.quote_asset,
-                                   self._limit_order_type, TradeType.SELL, sell.size, sell.price)
+                                   OrderType.LIMIT, TradeType.SELL, sell.size, sell.price)
             price = sell.price * (Decimal(1) + fee.percent)
             sell.price = market.c_quantize_order_price(self.trading_pair, price)
 
@@ -1036,15 +1161,13 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
             proposal is not None and \
             len(self.active_non_hanging_orders) == 0
 
-    cdef c_execute_orders_proposal(self, object proposal):
+    cdef c_execute_orders_proposal(self, object proposal, object position_action):
         cdef:
-            double expiration_seconds = (self._order_refresh_time
-                                         if ((self._market_info.market.name in self.RADAR_RELAY_TYPE_EXCHANGES) or
-                                             (self._market_info.market.name == "bamboo_relay" and
-                                              not self._market_info.market.use_coordinator))
-                                         else NaN)
+            double expiration_seconds = NaN
             str bid_order_id, ask_order_id
             bint orders_created = False
+            object order_type = self._close_position_order_type if position_action == PositionAction.CLOSE and \
+                self._position_management == "Trailing_stop" else OrderType.LIMIT
 
         if len(proposal.buys) > 0:
             if self._logging_options & self.OPTION_LOG_CREATE_ORDER:
@@ -1053,16 +1176,19 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
                                    for buy in proposal.buys]
                 self.logger().info(
                     f"({self.trading_pair}) Creating {len(proposal.buys)} bid orders "
-                    f"at (Size, Price): {price_quote_str}"
+                    f"at (Size, Price): {price_quote_str} to {position_action.name} position."
                 )
             for buy in proposal.buys:
                 bid_order_id = self.c_buy_with_specific_market(
                     self._market_info,
                     buy.size,
-                    order_type=self._limit_order_type,
+                    order_type=order_type,
                     price=buy.price,
-                    expiration_seconds=expiration_seconds
+                    expiration_seconds=expiration_seconds,
+                    position_action=position_action
                 )
+                if position_action == PositionAction.CLOSE:
+                    self._ts_exit_orders.append(bid_order_id)
                 orders_created = True
         if len(proposal.sells) > 0:
             if self._logging_options & self.OPTION_LOG_CREATE_ORDER:
@@ -1071,16 +1197,19 @@ cdef class PerpetualMarketMakingStrategy(StrategyBase):
                                    for sell in proposal.sells]
                 self.logger().info(
                     f"({self.trading_pair}) Creating {len(proposal.sells)} ask "
-                    f"orders at (Size, Price): {price_quote_str}"
+                    f"orders at (Size, Price): {price_quote_str} to {position_action.name} position."
                 )
             for sell in proposal.sells:
                 ask_order_id = self.c_sell_with_specific_market(
                     self._market_info,
                     sell.size,
-                    order_type=self._limit_order_type,
+                    order_type=order_type,
                     price=sell.price,
-                    expiration_seconds=expiration_seconds
+                    expiration_seconds=expiration_seconds,
+                    position_action=position_action
                 )
+                if position_action == PositionAction.CLOSE:
+                    self._ts_exit_orders.append(ask_order_id)
                 orders_created = True
         if orders_created:
             self.set_timers()
diff --git a/hummingbot/strategy/perpetual_market_making/perpetual_market_making_config_map.py b/hummingbot/strategy/perpetual_market_making/perpetual_market_making_config_map.py
index b9cfe4bf1f4..deb7e3d5b74 100644
--- a/hummingbot/strategy/perpetual_market_making/perpetual_market_making_config_map.py
+++ b/hummingbot/strategy/perpetual_market_making/perpetual_market_making_config_map.py
@@ -34,6 +34,11 @@ def validate_derivative_trading_pair(value: str) -> Optional[str]:
     return validate_market_trading_pair(derivative, value)
 
 
+def validate_derivative_position_mode(value: str) -> Optional[str]:
+    if value not in ["One-way", "Hedge"]:
+        return "Position mode can either be One-way or Hedge mode"
+
+
 def order_amount_prompt() -> str:
     derivative = perpetual_market_making_config_map["derivative"].value
     trading_pair = perpetual_market_making_config_map["market"].value
@@ -139,11 +144,10 @@ def derivative_on_validated(value: str):
                   prompt_on_new=True),
     "position_mode":
         ConfigVar(key="position_mode",
-                  prompt="Do you want to use hedge mode? "
-                         "(If disabled, one-way position mode would be used.) >>> ",
-                  type_str="bool",
-                  default=False,
-                  validator=validate_bool,
+                  prompt="Which position mode do you want to use? (One-way/Hedge) >>> ",
+                  validator=validate_derivative_position_mode,
+                  type_str="str",
+                  default="One-way",
                   prompt_on_new=True),
     "bid_spread":
         ConfigVar(key="bid_spread",
@@ -186,6 +190,55 @@ def derivative_on_validated(value: str):
                   type_str="decimal",
                   validator=validate_order_amount,
                   prompt_on_new=True),
+    "position_management":
+        ConfigVar(key="position_management",
+                  prompt="How would you like to manage your positions? (Profit_taking/Trailing_stop) >>> ",
+                  type_str="str",
+                  default="Profit_taking",
+                  validator=lambda s: None if s in {"Profit_taking", "Trailing_stop"} else
+                  "Invalid position management.",
+                  prompt_on_new=True),
+    "long_profit_taking_spread":
+        ConfigVar(key="long_profit_taking_spread",
+                  prompt="At what spread from the entry price do you want to place a short order to reduce position? (Enter 1 for 1%) >>> ",
+                  required_if=lambda: perpetual_market_making_config_map.get("position_management").value == "Profit_taking",
+                  type_str="decimal",
+                  default=Decimal("0"),
+                  validator=lambda v: validate_decimal(v, 0, 100, True),
+                  prompt_on_new=True),
+    "short_profit_taking_spread":
+        ConfigVar(key="short_profit_taking_spread",
+                  prompt="At what spread from the position entry price do you want to place a long order to reduce position? (Enter 1 for 1%) >>> ",
+                  required_if=lambda: perpetual_market_making_config_map.get("position_management").value == "Profit_taking",
+                  type_str="decimal",
+                  default=Decimal("0"),
+                  validator=lambda v: validate_decimal(v, 0, 100, True),
+                  prompt_on_new=True),
+    "ts_activation_spread":
+        ConfigVar(key="ts_activation_spread",
+                  prompt="At what spread from the position entry price do you want the bot to start trailing? (Enter 1 for 1%) >>> ",
+                  required_if=lambda: perpetual_market_making_config_map.get("position_management").value == "Trailing_stop",
+                  type_str="decimal",
+                  default=Decimal("0"),
+                  validator=lambda v: validate_decimal(v, 0, 100, True),
+                  prompt_on_new=True),
+    "ts_callback_rate":
+        ConfigVar(key="ts_callback_rate",
+                  prompt="At what spread away from the trailing peak price do you want to positions to remain open before they're closed? (Enter 1 for 1%) >>> ",
+                  required_if=lambda: perpetual_market_making_config_map.get("position_management").value == "Trailing_stop",
+                  type_str="decimal",
+                  default=Decimal("0"),
+                  validator=lambda v: validate_decimal(v, 0, 100, True),
+                  prompt_on_new=True),
+    "close_position_order_type":
+        ConfigVar(key="close_position_order_type",
+                  prompt="What order type do you want to use for closing positions? (LIMIT/MARKET) >>> ",
+                  required_if=lambda: perpetual_market_making_config_map.get("position_management").value == "Trailing_stop",
+                  type_str="str",
+                  default="LIMIT",
+                  validator=lambda s: None if s in {"LIMIT", "MARKET"} else
+                  "Invalid order type.",
+                  prompt_on_new=True),
     "price_ceiling":
         ConfigVar(key="price_ceiling",
                   prompt="Enter the price point above which only sell orders will be placed "
@@ -205,7 +258,6 @@ def derivative_on_validated(value: str):
                   prompt="Would you like to use the ping pong feature and alternate between buy and sell orders after fills? (Yes/No) >>> ",
                   type_str="bool",
                   default=False,
-                  prompt_on_new=True,
                   validator=validate_bool),
     "order_levels":
         ConfigVar(key="order_levels",
diff --git a/hummingbot/strategy/perpetual_market_making/start.py b/hummingbot/strategy/perpetual_market_making/start.py
index c059364288a..e4fa06e202b 100644
--- a/hummingbot/strategy/perpetual_market_making/start.py
+++ b/hummingbot/strategy/perpetual_market_making/start.py
@@ -23,6 +23,12 @@ def start(self):
         order_refresh_time = c_map.get("order_refresh_time").value
         bid_spread = c_map.get("bid_spread").value / Decimal('100')
         ask_spread = c_map.get("ask_spread").value / Decimal('100')
+        position_management = c_map.get("position_management").value
+        long_profit_taking_spread = c_map.get("long_profit_taking_spread").value / Decimal('100')
+        short_profit_taking_spread = c_map.get("short_profit_taking_spread").value / Decimal('100')
+        ts_activation_spread = c_map.get("ts_activation_spread").value / Decimal('100')
+        ts_callback_rate = c_map.get("ts_callback_rate").value / Decimal('100')
+        close_position_order_type = c_map.get("close_position_order_type").value
         minimum_spread = c_map.get("minimum_spread").value / Decimal('100')
         price_ceiling = c_map.get("price_ceiling").value
         price_floor = c_map.get("price_floor").value
@@ -75,6 +81,12 @@ def start(self):
             ask_spread=ask_spread,
             order_levels=order_levels,
             order_amount=order_amount,
+            position_management = position_management,
+            long_profit_taking_spread = long_profit_taking_spread,
+            short_profit_taking_spread = short_profit_taking_spread,
+            ts_activation_spread = ts_activation_spread,
+            ts_callback_rate = ts_callback_rate,
+            close_position_order_type = close_position_order_type,
             order_level_spread=order_level_spread,
             order_level_amount=order_level_amount,
             filled_order_delay=filled_order_delay,
diff --git a/hummingbot/strategy/strategy_base.pxd b/hummingbot/strategy/strategy_base.pxd
index dbe04003787..2ed151b74e4 100644
--- a/hummingbot/strategy/strategy_base.pxd
+++ b/hummingbot/strategy/strategy_base.pxd
@@ -36,10 +36,10 @@ cdef class StrategyBase(TimeIterator):
     cdef c_did_complete_buy_order_tracker(self, object order_completed_event)
     cdef c_did_complete_sell_order_tracker(self, object order_completed_event)
 
-    cdef str c_buy_with_specific_market(self, object market_trading_pair_tuple, object amount,
-                                        object order_type = *, object price = *, double expiration_seconds = *)
-    cdef str c_sell_with_specific_market(self, object market_trading_pair_tuple, object amount,
-                                         object order_type = *, object price = *, double expiration_seconds = *)
+    cdef str c_buy_with_specific_market(self, object market_trading_pair_tuple, object amount, object order_type = *,
+                                        object price = *, double expiration_seconds = *, position_action = *)
+    cdef str c_sell_with_specific_market(self, object market_trading_pair_tuple, object amount, object order_type = *,
+                                         object price = *, double expiration_seconds = *, position_action = *, )
     cdef c_cancel_order(self, object market_pair, str order_id)
 
     cdef c_start_tracking_limit_order(self, object market_pair, str order_id, bint is_buy, object price,
diff --git a/hummingbot/strategy/strategy_base.pyx b/hummingbot/strategy/strategy_base.pyx
index da29092e95a..4bc661693ce 100755
--- a/hummingbot/strategy/strategy_base.pyx
+++ b/hummingbot/strategy/strategy_base.pyx
@@ -14,7 +14,8 @@ from hummingbot.connector.connector_base cimport ConnectorBase
 from hummingbot.core.data_type.trade import Trade
 from hummingbot.core.event.events import (
     OrderFilledEvent,
-    OrderType
+    OrderType,
+    PositionAction
 )
 
 from .order_tracker import OrderTracker
@@ -366,16 +367,19 @@ cdef class StrategyBase(TimeIterator):
     def buy_with_specific_market(self, market_trading_pair_tuple, amount,
                                  order_type=OrderType.MARKET,
                                  price=s_decimal_nan,
-                                 expiration_seconds=NaN):
+                                 expiration_seconds=NaN,
+                                 position_action=PositionAction.OPEN):
         return self.c_buy_with_specific_market(market_trading_pair_tuple, amount,
                                                order_type,
                                                price,
-                                               expiration_seconds)
+                                               expiration_seconds,
+                                               position_action)
 
     cdef str c_buy_with_specific_market(self, object market_trading_pair_tuple, object amount,
                                         object order_type=OrderType.MARKET,
                                         object price=s_decimal_nan,
-                                        double expiration_seconds=NaN):
+                                        double expiration_seconds=NaN,
+                                        position_action=PositionAction.OPEN):
         if self._sb_delegate_lock:
             raise RuntimeError("Delegates are not allowed to execute orders directly.")
 
@@ -383,9 +387,8 @@ cdef class StrategyBase(TimeIterator):
             raise TypeError("price and amount must be Decimal objects.")
 
         cdef:
-            dict kwargs = {
-                "expiration_ts": self._current_timestamp + expiration_seconds
-            }
+            kwargs = {"expiration_ts": self._current_timestamp + expiration_seconds,
+                      "position_action": position_action}
             ConnectorBase market = market_trading_pair_tuple.market
 
         if market not in self._sb_markets:
@@ -409,16 +412,19 @@ cdef class StrategyBase(TimeIterator):
     def sell_with_specific_market(self, market_trading_pair_tuple, amount,
                                   order_type=OrderType.MARKET,
                                   price=s_decimal_nan,
-                                  expiration_seconds=NaN):
+                                  expiration_seconds=NaN,
+                                  position_action=PositionAction.OPEN):
         return self.c_sell_with_specific_market(market_trading_pair_tuple, amount,
                                                 order_type,
                                                 price,
-                                                expiration_seconds)
+                                                expiration_seconds,
+                                                position_action)
 
     cdef str c_sell_with_specific_market(self, object market_trading_pair_tuple, object amount,
                                          object order_type=OrderType.MARKET,
                                          object price=s_decimal_nan,
-                                         double expiration_seconds=NaN):
+                                         double expiration_seconds=NaN,
+                                         position_action=PositionAction.OPEN):
         if self._sb_delegate_lock:
             raise RuntimeError("Delegates are not allowed to execute orders directly.")
 
@@ -426,10 +432,8 @@ cdef class StrategyBase(TimeIterator):
             raise TypeError("price and amount must be Decimal objects.")
 
         cdef:
-            dict kwargs = {
-                "expiration_ts": self._current_timestamp + expiration_seconds
-            }
-
+            kwargs = {"expiration_ts": self._current_timestamp + expiration_seconds,
+                      "position_action": position_action}
             ConnectorBase market = market_trading_pair_tuple.market
 
         if market not in self._sb_markets:
diff --git a/hummingbot/templates/conf_perpetual_market_making_strategy_TEMPLATE.yml b/hummingbot/templates/conf_perpetual_market_making_strategy_TEMPLATE.yml
index aab10993738..7eaaf285170 100644
--- a/hummingbot/templates/conf_perpetual_market_making_strategy_TEMPLATE.yml
+++ b/hummingbot/templates/conf_perpetual_market_making_strategy_TEMPLATE.yml
@@ -2,7 +2,7 @@
 ###       Perpetual market making strategy config         ###
 ########################################################
 
-template_version: 2
+template_version: 3
 strategy: null
 
 # derivative and token parameters.
@@ -44,6 +44,24 @@ order_refresh_tolerance_pct: null
 # Size of your bid and ask order.
 order_amount: null
 
+# Which position management feature to use. Trailing stop and take profit features are currently supported
+position_management: null
+
+# long position take profit spread
+long_profit_taking_spread: null
+
+# short position take profit spread
+short_profit_taking_spread: null
+
+# Activation spread for trailing stop
+ts_activation_spread: null
+
+# Callback rate for trailing stop
+ts_callback_rate: null
+
+# OrderType to use for closing positions when using Trailing stop feature
+close_position_order_type: null
+
 # Price band ceiling.
 price_ceiling: null
 


Code review comments:
diff_hunk: @@ -186,6 +190,55 @@ def derivative_on_validated(value: str):
                   type_str="decimal",
                   validator=validate_order_amount,
                   prompt_on_new=True),
+    "position_management":
+        ConfigVar(key="position_management",
+                  prompt="How would you like to manage your positions? (Profit_taking/Trailing_stop) >>> ",
+                  type_str="str",
+                  default="Profit_taking",
+                  validator=lambda s: None if s in {"Profit_taking", "Trailing_stop"} else
+                  "Invalid position management.",
+                  prompt_on_new=True),
+    "long_profit_taking_spread":
+        ConfigVar(key="long_profit_taking_spread",
+                  prompt="At what spread from the entry price do you want to place a short order to reduce position? (Enter 1 for 1%) >>> ",
+                  required_if=lambda: perpetual_market_making_config_map.get("position_management").value == "Profit_taking",
+                  type_str="decimal",
+                  default=Decimal("0"),
+                  validator=lambda v: validate_decimal(v, 0, 100, True),
+                  prompt_on_new=True),
+    "short_profit_taking_spread":
+        ConfigVar(key="short_profit_taking_spread",
+                  prompt="At what spread from the position entry price do you want to place a long order to reduce position? (Enter 1 for 1%) >>> ",
+                  required_if=lambda: perpetual_market_making_config_map.get("position_management").value == "Profit_taking",
+                  type_str="decimal",
+                  default=Decimal("0"),
+                  validator=lambda v: validate_decimal(v, 0, 100, True),
+                  prompt_on_new=True),
+    "ts_activation_spread":
+        ConfigVar(key="ts_activation_spread",
+                  prompt="At what spread from the position entry price do you want the bot to start trailing? (Enter 1 for 1%) >>> ",
+                  required_if=lambda: perpetual_market_making_config_map.get("position_management").value == "Trailing_stop",
+                  type_str="decimal",
+                  default=Decimal("0"),
+                  validator=lambda v: validate_decimal(v, 0, 100, True),
+                  prompt_on_new=True),
+    "ts_callback_rate":
+        ConfigVar(key="ts_callback_rate",
+                  prompt="At what spread away from the trailing peak price do you want to positions to remain open before they're closed? (Enter 1 for 1%) >>> ",
path: hummingbot/strategy/perpetual_market_making/perpetual_market_making_config_map.py
text: @author:
```suggestion
                  prompt="At what spread away from the trailing peak price do you want positions to remain open before they're closed? (Enter 1 for 1%) >>> ",
```