mango-explorer/mango/marketmaking/orderchain/fixedspreadelement.py

74 lines
3.5 KiB
Python
Raw Normal View History

# # ⚠ Warning
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# [🥭 Mango Markets](https://mango.markets/) support is available at:
# [Docs](https://docs.mango.markets/)
# [Discord](https://discord.gg/67jySBhxrg)
# [Twitter](https://twitter.com/mangomarkets)
# [Github](https://github.com/blockworks-foundation)
# [Email](mailto:hello@blockworks.foundation)
import argparse
import mango
import typing
from decimal import Decimal
from .pairwiseelement import PairwiseElement
from ...modelstate import ModelState
# # 🥭 FixedSpreadElement class
#
# Ignores any input `Order`s (so probably best at the head of the chain). Builds orders using a fixed spread
# value.
#
class FixedSpreadElement(PairwiseElement):
def __init__(self, spreads: typing.Sequence[Decimal]):
super().__init__()
self.spreads: typing.Sequence[Decimal] = spreads
@staticmethod
def add_command_line_parameters(parser: argparse.ArgumentParser) -> None:
parser.add_argument("--fixedspread-value", type=Decimal, action="append",
help="fixed value to apply to the mid-price to create the BUY and SELL price. Can be specified multiple times for multiple levels of BUYs and SELLs.")
@staticmethod
def from_command_line_parameters(args: argparse.Namespace) -> "FixedSpreadElement":
if args.fixedspread_value is None:
raise Exception("No spread value specified. Try the --fixedspread-value parameter?")
spreads: typing.Sequence[Decimal] = args.fixedspread_value
return FixedSpreadElement(spreads)
def process_order_pair(self, context: mango.Context, model_state: ModelState, index: int, buy: typing.Optional[mango.Order], sell: typing.Optional[mango.Order]) -> typing.Tuple[typing.Optional[mango.Order], typing.Optional[mango.Order]]:
# If no spread is explicitly specified for this element, just use the last specified spread.
spread: Decimal = self.spreads[index] if index < len(self.spreads) else self.spreads[-1]
half_spread: Decimal = spread / 2
price: mango.Price = model_state.price
new_buy: typing.Optional[mango.Order] = None
new_sell: typing.Optional[mango.Order] = None
if buy is not None:
new_buy_price: Decimal = price.mid_price - half_spread
new_buy = buy.with_price(new_buy_price)
self.logger.debug(f"""Order change - using fixed spread of {spread:,.8f} - new BUY price {new_buy_price:,.8f} is {half_spread:,.8f} from mid price {price.mid_price:,.8f}:
Old: {buy}
New: {new_buy}""")
if sell is not None:
new_sell_price: Decimal = price.mid_price + half_spread
new_sell = sell.with_price(new_sell_price)
self.logger.debug(f"""Order change - using fixed spread of {spread:,.8f} - new SELL price {new_sell_price:,.8f} is {half_spread:,.8f} from mid price {price.mid_price:,.8f}:
Old: {sell}
New: {new_sell}""")
return new_buy, new_sell
def __str__(self) -> str:
return f"« 𝙵𝚒𝚡𝚎𝚍𝚂𝚙𝚛𝚎𝚊𝚍𝙴𝚕𝚎𝚖𝚎𝚗𝚝 using spreads {self.spreads} »"