Skip to content

Commit 8c07c84

Browse files
committed
[Position] fix position quantity size issues
tmp tmp tmp tmp tmp
1 parent 61a442a commit 8c07c84

File tree

9 files changed

+34
-41
lines changed

9 files changed

+34
-41
lines changed

octobot_trading/exchanges/traders/trader.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -670,11 +670,15 @@ async def set_position_mode(self, symbol, position_mode):
670670
is_hedge=position_mode is enums.PositionMode.HEDGE
671671
)
672672

673-
def _has_open_position(self, symbol):
673+
def _has_open_position(self, symbol) -> bool:
674674
"""
675675
Checks if open position exists for :symbol:
676676
:param symbol: the position symbol
677677
:return: True if open position for :symbol: exists
678678
"""
679-
return len(self.exchange_manager.exchange_personal_data.positions_manager.get_symbol_positions(
680-
symbol=symbol)) != 0
679+
for position in self.exchange_manager.exchange_personal_data.positions_manager.get_symbol_positions(
680+
symbol=symbol
681+
):
682+
if position.size:
683+
return True
684+
return False

octobot_trading/personal_data/positions/position.pxd

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ cdef class Position(util.Initializable):
4141
cdef public object exit_price
4242
cdef public object mark_price
4343
cdef public object liquidation_price
44-
cdef public object quantity
44+
cdef public object single_contract_value
4545
cdef public object size
4646
cdef public object already_reduced_size
4747
cdef public object value
@@ -65,7 +65,7 @@ cdef class Position(util.Initializable):
6565
object entry_price,
6666
object mark_price,
6767
object liquidation_price,
68-
object quantity,
68+
object single_contract_value,
6969
object size,
7070
object value,
7171
object initial_margin,

octobot_trading/personal_data/positions/position.py

+13-24
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def __init__(self, trader, symbol_contract):
6161
self.fee_to_close = constants.ZERO
6262

6363
# Size
64-
self.quantity = constants.ZERO
64+
self.single_contract_value = constants.ONE
6565
self.size = constants.ZERO
6666
self.already_reduced_size = constants.ZERO
6767
self.value = constants.ZERO
@@ -120,7 +120,7 @@ def _should_change(self, original_value, new_value):
120120

121121
def _update(self, position_id, symbol, currency, market, timestamp,
122122
entry_price, mark_price, liquidation_price,
123-
quantity, size, value, initial_margin,
123+
single_contract_value, size, value, initial_margin,
124124
unrealized_pnl, realised_pnl, fee_to_close,
125125
status=None):
126126
changed: bool = False
@@ -141,8 +141,8 @@ def _update(self, position_id, symbol, currency, market, timestamp,
141141
self.creation_time = self.exchange_manager.exchange.get_uniformized_timestamp(timestamp)
142142
self.timestamp = self.creation_time
143143

144-
if self._should_change(self.quantity, quantity):
145-
self.quantity = quantity
144+
if self._should_change(self.single_contract_value, single_contract_value):
145+
self.single_contract_value = single_contract_value
146146
changed = True
147147

148148
if self._should_change(self.size, size):
@@ -186,7 +186,6 @@ def _update(self, position_id, symbol, currency, market, timestamp,
186186
if self._should_change(self.status.value, status):
187187
self.status = enums.PositionStatus(status)
188188

189-
self._update_quantity_or_size_if_necessary()
190189
# update side after quantity as it relies on self.quantity
191190
self._update_side(not entry_price)
192191
self._update_prices_if_necessary(mark_price)
@@ -408,7 +407,6 @@ def _update_size(self, size_update, realised_pnl_update=constants.ZERO,
408407
size_update, is_closing=self._is_update_closing(size_update),
409408
update_price=self.mark_price, trigger_source=trigger_source)
410409
self._check_and_update_size(size_update)
411-
self._update_quantity()
412410
self._update_side(True)
413411
if self.exchange_manager.is_simulated:
414412
margin_update = self._update_initial_margin()
@@ -463,19 +461,10 @@ def _check_and_update_size(self, size_update):
463461
self.size += size_update
464462

465463
def _update_quantity_or_size_if_necessary(self):
466-
"""
467-
Set quantity from size if quantity is not set and size is set or update size
468-
"""
469-
if self.quantity == constants.ZERO and self.size != constants.ZERO:
470-
self._update_quantity()
471-
elif self.size == constants.ZERO and self.quantity != constants.ZERO:
472-
self.size = self.quantity * self.symbol_contract.current_leverage
464+
raise NotImplementedError("_update_quantity_or_size_if_necessary not implemented")
473465

474466
def _update_quantity(self):
475-
"""
476-
Update position quantity from position quantity
477-
"""
478-
self.quantity = self.size / self.symbol_contract.current_leverage
467+
raise NotImplementedError("_update_quantity not implemented")
479468

480469
def update_value(self):
481470
raise NotImplementedError("update_value not implemented")
@@ -647,7 +636,7 @@ def is_short(self):
647636
return self.side is enums.PositionSide.SHORT
648637

649638
def is_idle(self):
650-
return self.quantity == constants.ZERO
639+
return self.size == constants.ZERO
651640

652641
def get_quantity_to_close(self):
653642
"""
@@ -713,7 +702,7 @@ def update_from_raw(self, raw_position):
713702
mark_price=raw_position.get(enums.ExchangeConstantsPositionColumns.MARK_PRICE.value, constants.ZERO),
714703
liquidation_price=raw_position.get(enums.ExchangeConstantsPositionColumns.LIQUIDATION_PRICE.value,
715704
constants.ZERO),
716-
quantity=raw_position.get(enums.ExchangeConstantsPositionColumns.QUANTITY.value, constants.ZERO),
705+
single_contract_value=raw_position.get(enums.ExchangeConstantsPositionColumns.QUANTITY.value, constants.ONE),
717706
size=raw_position.get(enums.ExchangeConstantsPositionColumns.SIZE.value, constants.ZERO),
718707
value=raw_position.get(enums.ExchangeConstantsPositionColumns.NOTIONAL.value, constants.ZERO),
719708
initial_margin=raw_position.get(enums.ExchangeConstantsPositionColumns.INITIAL_MARGIN.value,
@@ -734,7 +723,7 @@ def to_dict(self):
734723
enums.ExchangeConstantsPositionColumns.STATUS.value: self.status.value,
735724
enums.ExchangeConstantsPositionColumns.TIMESTAMP.value: self.timestamp,
736725
enums.ExchangeConstantsPositionColumns.SIDE.value: self.side.value,
737-
enums.ExchangeConstantsPositionColumns.QUANTITY.value: self.quantity,
726+
enums.ExchangeConstantsPositionColumns.QUANTITY.value: self.single_contract_value,
738727
enums.ExchangeConstantsPositionColumns.SIZE.value: self.size,
739728
enums.ExchangeConstantsPositionColumns.NOTIONAL.value: self.value,
740729
enums.ExchangeConstantsPositionColumns.INITIAL_MARGIN.value: self.initial_margin,
@@ -778,11 +767,11 @@ def _update_side(self, reset_entry_price):
778767
"""
779768
if self.symbol_contract.is_one_way_position_mode() or self.side is enums.PositionSide.UNKNOWN:
780769
changed_side = False
781-
if self.quantity > constants.ZERO:
770+
if self.size > constants.ZERO:
782771
if self.side is not enums.PositionSide.LONG:
783772
self.side = enums.PositionSide.LONG
784773
changed_side = True
785-
elif self.quantity < constants.ZERO:
774+
elif self.size < constants.ZERO:
786775
if self.side is not enums.PositionSide.SHORT:
787776
self.side = enums.PositionSide.SHORT
788777
changed_side = True
@@ -822,7 +811,7 @@ async def reset(self):
822811
self.entry_price = constants.ZERO
823812
self.exit_price = constants.ZERO
824813
self.mark_price = constants.ZERO
825-
self.quantity = constants.ZERO
814+
self.single_contract_value = constants.ONE
826815
self.size = constants.ZERO
827816
self.already_reduced_size = constants.ZERO
828817
self.value = constants.ZERO
@@ -858,7 +847,7 @@ def restore(self, other_position):
858847
self.mark_price = other_position.mark_price
859848
self.liquidation_price = other_position.liquidation_price
860849
self.fee_to_close = other_position.fee_to_close
861-
self.quantity = other_position.quantity
850+
self.single_contract_value = other_position.single_contract_value
862851
self.size = other_position.size
863852
self.already_reduced_size = other_position.already_reduced_size
864853
self.value = other_position.value

octobot_trading/personal_data/positions/types/inverse_position.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def update_value(self):
2626
Notional value = CONTRACT_QUANTITY / MARK_PRICE
2727
"""
2828
try:
29-
self.value = self.size / self.mark_price
29+
self.value = self.size * self.single_contract_value / self.mark_price
3030
except (decimal.DivisionByZero, decimal.InvalidOperation):
3131
self.value = constants.ZERO
3232

octobot_trading/personal_data/positions/types/linear_position.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def update_value(self):
2525
"""
2626
Notional value = CONTRACT_QUANTITY * MARK_PRICE
2727
"""
28-
self.value = self.size * self.mark_price
28+
self.value = self.size * self.single_contract_value * self.mark_price
2929

3030
def get_unrealized_pnl(self, price):
3131
"""

tests/personal_data/orders/test_order_util.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ async def test_ensure_orders_relevancy_with_positions(future_trader_simulator_wi
446446
position.side = "other_other_side"
447447
trader_mock.cancel_order.assert_not_called()
448448
# with a non-0 quantity position
449-
position.quantity = decimal.Decimal("2")
449+
position.size = decimal.Decimal("2")
450450
# with position parameter
451451
async with personal_data.ensure_orders_relevancy(position=position):
452452
# changing side

tests/personal_data/positions/test_position.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -155,24 +155,24 @@ async def test_update_entry_price_when_switching_side_on_one_way(btc_usdt_future
155155
async def test_update_update_quantity(btc_usdt_future_trader_simulator_with_default_linear):
156156
config, exchange_manager_inst, trader_inst, default_contract, position_inst = btc_usdt_future_trader_simulator_with_default_linear
157157

158-
assert position_inst.quantity == constants.ZERO
158+
assert position_inst.size == constants.ZERO
159159

160160
quantity = decimal_random_quantity(1)
161161
await position_inst.update(update_size=quantity)
162-
assert position_inst.quantity == quantity
162+
assert position_inst.size == quantity
163163

164164

165165
async def test_invalid_update(btc_usdt_future_trader_simulator_with_default_linear):
166166
config, exchange_manager_inst, trader_inst, default_contract, position_inst = btc_usdt_future_trader_simulator_with_default_linear
167167
portfolio = exchange_manager_inst.exchange_personal_data.portfolio_manager.portfolio.get_currency_portfolio("BTC")
168168

169-
assert position_inst.quantity == constants.ZERO
169+
assert position_inst.size == constants.ZERO
170170

171171
async def _ensure_no_position_change(mark_price, update_size):
172172
with pytest.raises(errors.PortfolioNegativeValueError):
173173
await position_inst.update(mark_price=mark_price, update_size=update_size)
174174
# Did not affect position or portfolio data
175-
assert position_inst.quantity == position_inst.entry_price == position_inst.mark_price == position_inst.size == \
175+
assert position_inst.size == position_inst.entry_price == position_inst.mark_price == position_inst.size == \
176176
constants.ZERO
177177
assert portfolio.available == decimal.Decimal('10')
178178
assert portfolio.total == decimal.Decimal('10')

tests/personal_data/positions/test_position_factory.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ async def test_create_position_instance_from_raw(future_trader_simulator_with_de
4141
get_default_future_inverse_contract())
4242
inverse_position_open = personal_data.create_position_instance_from_raw(trader_inst, {
4343
enums.ExchangeConstantsPositionColumns.SYMBOL.value: DEFAULT_FUTURE_SYMBOL,
44-
enums.ExchangeConstantsPositionColumns.QUANTITY.value: position_quantity
44+
enums.ExchangeConstantsPositionColumns.SIZE.value: position_quantity
4545
})
4646
assert position.symbol == DEFAULT_FUTURE_SYMBOL
4747
assert position.market == "USDT"
@@ -50,7 +50,7 @@ async def test_create_position_instance_from_raw(future_trader_simulator_with_de
5050
assert isinstance(position, personal_data.LinearPosition)
5151

5252
assert inverse_position_open.status == enums.PositionStatus.OPEN
53-
assert inverse_position_open.quantity == position_quantity
53+
assert inverse_position_open.size == position_quantity
5454
assert isinstance(inverse_position_open, personal_data.InversePosition)
5555

5656

tests/personal_data/trades/test_trade_factory.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,11 @@ async def test_create_trade_from_order(self):
191191
assert trade.origin_order_id == '362550114'
192192
assert trade.trade_type == TraderOrderType.SELL_MARKET
193193
assert trade.symbol == 'UNI/USDT'
194-
assert trade.total_cost == ZERO
194+
assert trade.total_cost == decimal.Decimal("202338000")
195195
assert trade.executed_quantity == decimal.Decimal("44964.0")
196196
assert trade.origin_quantity == decimal.Decimal("44964.0")
197-
assert trade.origin_price == ZERO
198-
assert trade.executed_price == ZERO
197+
assert trade.origin_price == decimal.Decimal("4500")
198+
assert trade.executed_price == decimal.Decimal("4500")
199199
assert trade.status == OrderStatus.FILLED
200200
assert trade.executed_time == 1637579281.377
201201
assert trade.is_closing_order is True

0 commit comments

Comments
 (0)