Skip to content

Commit fa355ef

Browse files
committed
Re-Import Orig PMM
1 parent f7b5a64 commit fa355ef

19 files changed

+2276
-1
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env python
2+
3+
from .pure_market_making import PureMarketMakingStrategy
4+
from .asset_price_delegate import AssetPriceDelegate
5+
from .order_book_asset_price_delegate import OrderBookAssetPriceDelegate
6+
from .api_asset_price_delegate import APIAssetPriceDelegate
7+
from .inventory_cost_price_delegate import InventoryCostPriceDelegate
8+
__all__ = [
9+
PureMarketMakingStrategy,
10+
AssetPriceDelegate,
11+
OrderBookAssetPriceDelegate,
12+
APIAssetPriceDelegate,
13+
InventoryCostPriceDelegate,
14+
]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .asset_price_delegate cimport AssetPriceDelegate
2+
3+
cdef class APIAssetPriceDelegate(AssetPriceDelegate):
4+
cdef object _custom_api_feed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from .asset_price_delegate cimport AssetPriceDelegate
2+
from hummingbot.data_feed.custom_api_data_feed import CustomAPIDataFeed, NetworkStatus
3+
4+
cdef class APIAssetPriceDelegate(AssetPriceDelegate):
5+
def __init__(self, api_url: str):
6+
super().__init__()
7+
self._custom_api_feed = CustomAPIDataFeed(api_url=api_url)
8+
self._custom_api_feed.start()
9+
10+
cdef object c_get_mid_price(self):
11+
return self._custom_api_feed.get_price()
12+
13+
@property
14+
def ready(self) -> bool:
15+
return self._custom_api_feed.network_status == NetworkStatus.CONNECTED
16+
17+
@property
18+
def custom_api_feed(self) -> CustomAPIDataFeed:
19+
return self._custom_api_feed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
cdef class AssetPriceDelegate:
3+
cdef object c_get_mid_price(self)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from decimal import Decimal
2+
3+
4+
cdef class AssetPriceDelegate:
5+
# The following exposed Python functions are meant for unit tests
6+
# ---------------------------------------------------------------
7+
def get_mid_price(self) -> Decimal:
8+
return self.c_get_mid_price()
9+
# ---------------------------------------------------------------
10+
11+
cdef object c_get_mid_price(self):
12+
raise NotImplementedError
13+
14+
@property
15+
def ready(self) -> bool:
16+
raise NotImplementedError
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env python
2+
from typing import (
3+
NamedTuple,
4+
List
5+
)
6+
from decimal import Decimal
7+
from hummingbot.core.event.events import OrderType
8+
9+
ORDER_PROPOSAL_ACTION_CREATE_ORDERS = 1
10+
ORDER_PROPOSAL_ACTION_CANCEL_ORDERS = 1 << 1
11+
12+
13+
class OrdersProposal(NamedTuple):
14+
actions: int
15+
buy_order_type: OrderType
16+
buy_order_prices: List[Decimal]
17+
buy_order_sizes: List[Decimal]
18+
sell_order_type: OrderType
19+
sell_order_prices: List[Decimal]
20+
sell_order_sizes: List[Decimal]
21+
cancel_order_ids: List[str]
22+
23+
24+
class PricingProposal(NamedTuple):
25+
buy_order_prices: List[Decimal]
26+
sell_order_prices: List[Decimal]
27+
28+
29+
class SizingProposal(NamedTuple):
30+
buy_order_sizes: List[Decimal]
31+
sell_order_sizes: List[Decimal]
32+
33+
34+
class InventorySkewBidAskRatios(NamedTuple):
35+
bid_ratio: float
36+
ask_ratio: float
37+
38+
39+
class PriceSize:
40+
def __init__(self, price: Decimal, size: Decimal):
41+
self.price: Decimal = price
42+
self.size: Decimal = size
43+
44+
def __repr__(self):
45+
return f"[ p: {self.price} s: {self.size} ]"
46+
47+
48+
class Proposal:
49+
def __init__(self, buys: List[PriceSize], sells: List[PriceSize]):
50+
self.buys: List[PriceSize] = buys
51+
self.sells: List[PriceSize] = sells
52+
53+
def __repr__(self):
54+
return f"{len(self.buys)} buys: {', '.join([str(o) for o in self.buys])} " \
55+
f"{len(self.sells)} sells: {', '.join([str(o) for o in self.sells])}"
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from decimal import Decimal, InvalidOperation
2+
from typing import Optional
3+
4+
from hummingbot.core.event.events import OrderFilledEvent, TradeType
5+
from hummingbot.model.inventory_cost import InventoryCost
6+
from hummingbot.model.sql_connection_manager import SQLConnectionManager
7+
8+
s_decimal_0 = Decimal("0")
9+
10+
11+
class InventoryCostPriceDelegate:
12+
def __init__(self, sql: SQLConnectionManager, trading_pair: str) -> None:
13+
self.base_asset, self.quote_asset = trading_pair.split("-")
14+
self._session = sql.get_shared_session()
15+
16+
@property
17+
def ready(self) -> bool:
18+
return True
19+
20+
def get_price(self) -> Optional[Decimal]:
21+
record = InventoryCost.get_record(
22+
self._session, self.base_asset, self.quote_asset
23+
)
24+
25+
if record is None or record.base_volume is None or record.base_volume is None:
26+
return None
27+
28+
try:
29+
price = record.quote_volume / record.base_volume
30+
except InvalidOperation:
31+
# decimal.InvalidOperation: [<class 'decimal.DivisionUndefined'>] - both volumes are 0
32+
return None
33+
return Decimal(price)
34+
35+
def process_order_fill_event(self, fill_event: OrderFilledEvent) -> None:
36+
base_asset, quote_asset = fill_event.trading_pair.split("-")
37+
quote_volume = fill_event.amount * fill_event.price
38+
base_volume = fill_event.amount
39+
40+
for fee_asset, fee_amount in fill_event.trade_fee.flat_fees:
41+
if fill_event.trade_type == TradeType.BUY:
42+
if fee_asset == base_asset:
43+
base_volume -= fee_amount
44+
elif fee_asset == quote_asset:
45+
quote_volume += fee_amount
46+
else:
47+
# Ok, some other asset used (like BNB), assume that we paid in base asset for simplicity
48+
base_volume /= 1 + fill_event.trade_fee.percent
49+
else:
50+
if fee_asset == base_asset:
51+
base_volume += fee_amount
52+
elif fee_asset == quote_asset:
53+
# TODO: with new logic, this quote volume adjustment does not impacts anything
54+
quote_volume -= fee_amount
55+
else:
56+
# Ok, some other asset used (like BNB), assume that we paid in base asset for simplicity
57+
base_volume /= 1 + fill_event.trade_fee.percent
58+
59+
if fill_event.trade_type == TradeType.SELL:
60+
record = InventoryCost.get_record(self._session, base_asset, quote_asset)
61+
if not record:
62+
raise RuntimeError("Sold asset without having inventory price set. This should not happen.")
63+
64+
# We're keeping initial buy price intact. Profits are not changing inventory price intentionally.
65+
quote_volume = -(Decimal(record.quote_volume / record.base_volume) * base_volume)
66+
base_volume = -base_volume
67+
68+
InventoryCost.add_volume(
69+
self._session, base_asset, quote_asset, base_volume, quote_volume
70+
)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
cdef object c_calculate_bid_ask_ratios_from_base_asset_ratio(double base_asset_amount,
2+
double quote_asset_amount,
3+
double price,
4+
double target_base_asset_ratio,
5+
double base_asset_range)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from decimal import Decimal
2+
import numpy as np
3+
4+
from .data_types import InventorySkewBidAskRatios
5+
6+
decimal_0 = Decimal(0)
7+
decimal_1 = Decimal(1)
8+
decimal_2 = Decimal(2)
9+
10+
11+
def calculate_total_order_size(order_start_size: Decimal, order_step_size: Decimal = decimal_0,
12+
order_levels: int = 1) -> Decimal:
13+
order_levels_decimal = order_levels
14+
return (decimal_2 *
15+
(order_levels_decimal * order_start_size +
16+
order_levels_decimal * (order_levels_decimal - decimal_1) / decimal_2 * order_step_size
17+
)
18+
)
19+
20+
21+
def calculate_bid_ask_ratios_from_base_asset_ratio(
22+
base_asset_amount: float, quote_asset_amount: float, price: float,
23+
target_base_asset_ratio: float, base_asset_range: float) -> InventorySkewBidAskRatios:
24+
return c_calculate_bid_ask_ratios_from_base_asset_ratio(base_asset_amount,
25+
quote_asset_amount,
26+
price,
27+
target_base_asset_ratio,
28+
base_asset_range)
29+
30+
31+
cdef object c_calculate_bid_ask_ratios_from_base_asset_ratio(
32+
double base_asset_amount, double quote_asset_amount, double price,
33+
double target_base_asset_ratio, double base_asset_range):
34+
cdef:
35+
double total_portfolio_value = base_asset_amount * price + quote_asset_amount
36+
37+
if total_portfolio_value <= 0.0 or base_asset_range <= 0.0:
38+
return InventorySkewBidAskRatios(0.0, 0.0)
39+
40+
cdef:
41+
double base_asset_value = base_asset_amount * price
42+
double base_asset_range_value = min(base_asset_range * price, total_portfolio_value * 0.5)
43+
double target_base_asset_value = total_portfolio_value * target_base_asset_ratio
44+
double left_base_asset_value_limit = max(target_base_asset_value - base_asset_range_value, 0.0)
45+
double right_base_asset_value_limit = target_base_asset_value + base_asset_range_value
46+
double left_inventory_ratio = np.interp(base_asset_value,
47+
[left_base_asset_value_limit, target_base_asset_value],
48+
[0.0, 0.5])
49+
double right_inventory_ratio = np.interp(base_asset_value,
50+
[target_base_asset_value, right_base_asset_value_limit],
51+
[0.5, 1.0])
52+
double bid_adjustment = (np.interp(left_inventory_ratio, [0, 0.5], [2.0, 1.0])
53+
if base_asset_value < target_base_asset_value
54+
else np.interp(right_inventory_ratio, [0.5, 1], [1.0, 0.0]))
55+
double ask_adjustment = 2.0 - bid_adjustment
56+
57+
return InventorySkewBidAskRatios(bid_adjustment, ask_adjustment)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from .asset_price_delegate cimport AssetPriceDelegate
2+
from hummingbot.connector.exchange_base cimport ExchangeBase
3+
4+
cdef class OrderBookAssetPriceDelegate(AssetPriceDelegate):
5+
cdef:
6+
ExchangeBase _market
7+
str _trading_pair

0 commit comments

Comments
 (0)