Expanded porcelain functions, cleaned up old usage.

This commit is contained in:
Geoff Taylor 2022-02-24 19:40:05 +00:00
parent eb3d2465ef
commit eef007758d
81 changed files with 182 additions and 432 deletions

View File

@ -11,8 +11,6 @@ from solana.publickey import PublicKey
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(
description="Run the Account Scout to display problems and information about an account."
)

View File

@ -75,11 +75,7 @@ args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
instrument = context.instrument_lookup.find_by_symbol(args.symbol)
if instrument is None:
raise Exception(f"Could not find instrument with symbol '{args.symbol}'.")
token: mango.Token = mango.Token.ensure(instrument)
token: mango.Token = mango.token(context, args.symbol)
# The loaded `token` variable will be from the `context`, so if it's SOL it will be
# 'wrapped SOL' with a 1112 mint address, not regular SOL with a 1111 mint address.

View File

@ -83,7 +83,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
ops = mango.operations(
context, wallet, account, market_symbol, args.dry_run
)
orderbook = ops.fetch_orderbook(context)
orderbook = ops.load_orderbook()
price = orderbook.mid_price
if price is None:
raise Exception(

View File

@ -13,8 +13,6 @@ from solana.publickey import PublicKey
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(
description="Balance the value of tokens in a Mango Markets group to specific values or percentages."
)
@ -74,27 +72,16 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
targets: typing.Sequence[mango.FixedTargetBalance] = args.target
logging.info(f"Targets: {targets}")
quote_instrument: typing.Optional[
mango.Instrument
] = context.instrument_lookup.find_by_symbol(args.quote_symbol)
if quote_instrument is None:
raise Exception(f"Could not find quote token '{args.quote_symbol}.")
quote_token: mango.Token = mango.Token.ensure(quote_instrument)
quote_token = mango.token(context, args.quote_symbol)
prices: typing.List[mango.InstrumentValue] = []
oracle_provider: mango.OracleProvider = mango.create_oracle_provider(
context, "market"
)
for target in targets:
target_token: typing.Optional[
mango.Instrument
] = context.instrument_lookup.find_by_symbol(target.symbol)
if target_token is None:
raise Exception(f"Could not find target token '{target.symbol}.")
target_token = mango.token(context, target.symbol)
market_symbol: str = f"serum:{target_token.symbol}/{quote_token.symbol}"
market = context.market_lookup.find_by_symbol(market_symbol)
if market is None:
raise Exception(f"Could not find market {market_symbol}")
market = mango.market(context, market_symbol)
oracle = oracle_provider.oracle_for_market(context, market)
if oracle is None:
raise Exception(f"Could not find oracle for market {market_symbol}")

View File

@ -56,14 +56,9 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
mango.output(f"No open orders on {market_operations.market.symbol}")
else:
if mango.PerpMarket.isa(market_operations.market):
instruction_builder = mango.PerpMarketInstructionBuilder(
context,
wallet,
mango.PerpMarket.ensure(market_operations.market),
group,
account,
)
cancel_all = instruction_builder.build_cancel_all_orders_instructions()
cancel_all = mango.PerpMarketOperations.ensure(
market_operations
).market_instruction_builder.build_cancel_all_orders_instructions()
signers: mango.CombinableInstructions = (
mango.CombinableInstructions.from_wallet(wallet)

View File

@ -28,10 +28,7 @@ args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
wrapped_sol: mango.Token = mango.Token.ensure(
context.instrument_lookup.find_by_symbol_or_raise("SOL")
)
wrapped_sol: mango.Token = mango.token(context, "SOL")
token_account: typing.Optional[mango.TokenAccount] = mango.TokenAccount.load(
context, args.address
)

View File

@ -41,7 +41,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
context, wallet.address, group, args.account_address
)
deposit_value = mango.InstrumentValue(context.token(args.symbol), args.quantity)
deposit_value = mango.instrument_value(context, args.symbol, args.quantity)
signatures = account.deposit(context, wallet, deposit_value)
if args.wait:

View File

@ -23,7 +23,6 @@ args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
group = mango.Group.load(context)
accounts = mango.Account.load_all_for_owner(context, wallet.address, group)

View File

@ -30,11 +30,7 @@ args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
instrument = context.instrument_lookup.find_by_symbol(args.symbol)
if instrument is None:
raise Exception(f"Could not find instrument with symbol '{args.symbol}'.")
token: mango.Token = mango.Token.ensure(instrument)
token: mango.Token = mango.token(context, args.symbol)
associated_token_address = spl_token.get_associated_token_address(
wallet.address, token.mint

View File

@ -43,6 +43,4 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
context, wallet, account, args.market, args.dry_run
)
open_orders = market_operations.ensure_openorders()
mango.output(
f"OpenOrders account for {market_operations.market.symbol} is {open_orders}"
)
mango.output(f"OpenOrders account for {market_operations.symbol} is {open_orders}")

View File

@ -12,8 +12,6 @@ from solana.publickey import PublicKey
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(description="Liquidate a single margin account.")
mango.ContextBuilder.add_command_line_parameters(parser)
mango.Wallet.add_command_line_parameters(parser)

View File

@ -16,8 +16,6 @@ from decimal import Decimal
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(
description="Run a liquidator for a Mango Markets group."
)

View File

@ -10,8 +10,6 @@ import time
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(
description="Run a single pass of the liquidator for a Mango Markets group."
)

View File

@ -52,9 +52,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
context, wallet.address, group, args.account_address
)
ops: mango.MarketOperations = mango.operations(
context, wallet, account, args.symbol, args.dry_run
)
ops = mango.operations(context, wallet, account, args.symbol, args.dry_run)
signatures = ops.market_buy(args.quantity, args.max_slippage)
if args.wait:

View File

@ -54,9 +54,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
context, wallet.address, group, args.account_address
)
ops: mango.MarketOperations = mango.operations(
context, wallet, account, args.symbol, args.dry_run
)
ops = mango.operations(context, wallet, account, args.symbol, args.dry_run)
signatures = ops.market_buy(args.quantity, args.max_slippage)
if args.wait:

View File

@ -216,7 +216,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
context, wallet.address, group, args.account_address
)
market = mango.load_market_by_symbol(context, args.market)
market = mango.market(context, args.market)
# The market index is also the index of the base token in the group's token list.
if market.quote != group.shared_quote_token:
@ -235,28 +235,28 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
underlying_market = mango.PerpMarket.ensure(market)
hedging_market_operations: mango.MarketOperations = mango.operations(
hedging_ops = mango.operations(
context, wallet, account, args.hedging_market, args.dry_run
)
if not isinstance(hedging_market_operations, mango.SpotMarketOperations):
if not isinstance(hedging_ops, mango.SpotMarketOperations):
raise Exception(
f"MarketOperations for {args.hedging_market} is not a SpotMarketOperations."
)
logging.info(f"Hedging on {hedging_market_operations.market.symbol}")
logging.info(f"Hedging on {hedging_ops.market.symbol}")
target_balance: typing.Optional[
mango.TargetBalance
] = args.hedging_target_balance
if target_balance is None:
target_balance = mango.FixedTargetBalance(
hedging_market_operations.market.base.symbol, Decimal(0)
hedging_ops.market.base.symbol, Decimal(0)
)
hedger = mango.hedging.PerpToSpotHedger(
group,
underlying_market,
mango.SpotMarket.ensure(hedging_market_operations.market),
hedging_market_operations,
mango.SpotMarket.ensure(hedging_ops.market),
hedging_ops,
args.hedging_max_price_slippage_factor,
args.hedging_max_chunk_quantity,
target_balance,
@ -305,7 +305,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
oracle_market: mango.LoadedMarket = (
market
if args.oracle_market is None
else mango.load_market_by_symbol(context, args.oracle_market)
else mango.market(context, args.oracle_market)
)
oracle = oracle_provider.oracle_for_market(context, oracle_market)
if oracle is None:

View File

@ -38,11 +38,7 @@ args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
instrument = context.instrument_lookup.find_by_symbol(args.symbol)
if instrument is None:
raise Exception(f"Could not find instrument with symbol '{args.symbol}'.")
token: mango.Token = mango.Token.ensure(instrument)
token: mango.Token = mango.token(context, args.symbol)
spl_token = SolanaSPLToken(
context.client.compatible_client, token.mint, TOKEN_PROGRAM_ID, wallet.keypair

View File

@ -37,11 +37,9 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
account_info = mango.AccountInfo.load(context, args.address)
if account_info is None:
raise Exception(f"No account at '{args.address}'")
else:
if account_info.sols < args.minimum_sol_balance:
notify: mango.NotificationTarget = mango.CompoundNotificationTarget(
args.notify
)
report = f'Account "{args.name} [{args.address}]" on {context.client.cluster_name} has only {account_info.sols} SOL, which is below the minimum required balance of {args.minimum_sol_balance} SOL.'
notify.send(report)
mango.output(f"Notification sent: {report}")
if account_info.sols < args.minimum_sol_balance:
notify: mango.NotificationTarget = mango.CompoundNotificationTarget(args.notify)
report = f'Account "{args.name} [{args.address}]" on {context.client.cluster_name} has only {account_info.sols} SOL, which is below the minimum required balance of {args.minimum_sol_balance} SOL.'
notify.send(report)
mango.output(f"Notification sent: {report}")

View File

@ -140,14 +140,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
context, wallet, group, mngo, account, perp_market, basket_token
)
else:
market = context.market_lookup.find_by_symbol(args.market)
if market is None:
raise Exception(f"Could not find market {args.market}")
perp_market = mango.PerpMarket.ensure(
mango.ensure_market_loaded(context, market)
)
perp_market = mango.PerpMarket.ensure(mango.market(context, args.market))
basket_token = find_basket_token_in_account(account, perp_market.base)
all_instructions += build_redeem_instruction_for_account(
context, wallet, group, mngo, account, perp_market, basket_token

View File

@ -16,8 +16,6 @@ from solana.publickey import PublicKey
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(
description="Run the Transaction Scout to display information about a specific transaction."
)

View File

@ -10,8 +10,6 @@ import traceback
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(description="Sends SOL to a different address.")
parser.add_argument(
"--notification-target",

View File

@ -14,8 +14,6 @@ from solana.transaction import Transaction
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(description="Sends SOL to a different address.")
mango.ContextBuilder.add_command_line_parameters(parser)
mango.Wallet.add_command_line_parameters(parser)

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python3
import argparse
import logging
import os
import os.path
import sys
@ -16,8 +15,6 @@ from spl.token.constants import ACCOUNT_LEN, TOKEN_PROGRAM_ID
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(description="Sends SPL tokens to a different address.")
mango.ContextBuilder.add_command_line_parameters(parser)
mango.Wallet.add_command_line_parameters(parser)
@ -48,13 +45,7 @@ args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
logging.info(f"Wallet address: {wallet.address}")
instrument = context.instrument_lookup.find_by_symbol(args.symbol)
if instrument is None:
raise Exception(f"Could not find details of token with symbol {args.symbol}.")
token: mango.Token = mango.Token.ensure(instrument)
token: mango.Token = mango.token(context, args.symbol)
spl_token = SolanaSPLToken(
context.client.compatible_client, token.mint, TOKEN_PROGRAM_ID, wallet.keypair

View File

@ -9,10 +9,8 @@ import sys
from solana.publickey import PublicKey
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
import mango
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(
description="Settles all openorders transactions in the Group."
)

View File

@ -42,11 +42,10 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
balances += [mango.InstrumentValue(mango.SolToken, sol_balance)]
for slot_token_bank in group.tokens:
if isinstance(slot_token_bank.token, mango.Token):
balance = mango.InstrumentValue.fetch_total_value(
context, address, slot_token_bank.token
)
balances += [balance]
balance = mango.InstrumentValue.fetch_total_value(
context, address, slot_token_bank.token
)
balances += [balance]
mango.output(f"\nToken Balances [{address}]:")
total_in_wallet: mango.InstrumentValue = mango.InstrumentValue(

View File

@ -22,12 +22,5 @@ parser.add_argument(
args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
group = mango.Group.load(context)
market = context.market_lookup.find_by_symbol(args.market)
if market is None:
raise Exception(f"Could not find market {args.market}")
perp_market = mango.PerpMarket.ensure(mango.ensure_market_loaded(context, market))
perp_market = mango.PerpMarket.ensure(mango.market(context, args.market))
mango.output(perp_market.fetch_funding(context))

View File

@ -24,11 +24,7 @@ args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
group = mango.Group.load(context)
token = context.instrument_lookup.find_by_symbol(args.symbol)
if token is None:
raise Exception(f"Could not find token {args.symbol} in group {group.address}")
token = mango.token(context, args.symbol)
token_bank = group.token_bank_by_instrument(token)
interest_rates = token_bank.fetch_interest_rates(context)
mango.output(interest_rates)

View File

@ -21,10 +21,5 @@ parser.add_argument(
args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
market = context.market_lookup.find_by_symbol(args.market)
if market is None:
raise Exception(f"Could not find market {args.market}")
actual_market = mango.PerpMarket.ensure(mango.ensure_market_loaded(context, market))
mango.output(actual_market.underlying_perp_market.liquidity_mining_info)
perp_market = mango.PerpMarket.ensure(mango.market(context, args.market))
mango.output(perp_market.underlying_perp_market.liquidity_mining_info)

View File

@ -16,9 +16,5 @@ parser.add_argument(
args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
market = context.market_lookup.find_by_symbol(args.market)
if market is None:
raise Exception(f"Could not find market {args.market}")
actual_market = mango.ensure_market_loaded(context, market)
mango.output(actual_market)
market = mango.market(context, args.market)
mango.output(market)

View File

@ -42,11 +42,7 @@ with mango.ContextBuilder.from_command_line_parameters(
context, wallet.address, group, args.account_address
)
market = context.market_lookup.find_by_symbol(args.market)
if market is None:
raise Exception(f"Could not find market {args.market}")
market = mango.ensure_market_loaded(context, market)
market = mango.market(context, args.market)
oracle_provider: mango.OracleProvider = mango.create_oracle_provider(
context, args.oracle_provider

View File

@ -26,12 +26,12 @@ parser.add_argument(
)
args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
address: typing.Optional[PublicKey] = args.address
if address is None:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
address = wallet.address
address: typing.Optional[PublicKey] = args.address
if address is None:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
address = wallet.address
with mango.ContextBuilder.from_command_line_parameters(args) as context:
group = mango.Group.load(context)
account = mango.Account.load_for_owner_by_address(
context, wallet.address, group, args.account_address

View File

@ -21,12 +21,6 @@ parser.add_argument(
type=PublicKey,
help="address of the specific account to use, if more than one available",
)
parser.add_argument(
"--dry-run",
action="store_true",
default=False,
help="runs as read-only and does not perform any transactions",
)
args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
@ -36,7 +30,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
context, wallet.address, group, args.account_address
)
market = mango.load_market_by_symbol(context, args.market)
market = mango.market(context, args.market)
orderbook = market.fetch_orderbook(context)
mango.output(orderbook)

View File

@ -34,10 +34,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
context, args.provider
)
market = context.market_lookup.find_by_symbol(args.market)
if market is None:
raise Exception(f"Could not find market {args.market}.")
market = mango.market(context, args.market)
oracle = oracle_provider.oracle_for_market(context, market)
if oracle is None:
mango.output(

View File

@ -30,11 +30,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
address = wallet.address
stub = context.market_lookup.find_by_symbol(args.market)
if stub is None:
raise Exception(f"Could not find market {args.market}")
market = mango.SerumMarket.ensure(mango.ensure_market_loaded(context, stub))
market = mango.SerumMarket.ensure(mango.market(context, args.market))
all_open_orders_for_market = mango.OpenOrders.load_for_market_and_owner(
context,

View File

@ -42,10 +42,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
if args.mint is not None:
token = mango.Token(args.symbol, args.symbol, args.decimals, args.mint)
else:
instrument: mango.Instrument = (
context.instrument_lookup.find_by_symbol_or_raise(args.symbol)
)
token = mango.Token.ensure(instrument)
token = mango.token(context, args.symbol)
token_accounts: typing.Sequence[
mango.TokenAccount
] = mango.TokenAccount.fetch_all_for_owner_and_token(context, owner_address, token)

View File

@ -16,11 +16,7 @@ args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
wrapped_sol: mango.Token = mango.Token.ensure(
context.instrument_lookup.find_by_symbol_or_raise("SOL")
)
wrapped_sol: mango.Token = mango.token(context, "SOL")
token_accounts = mango.TokenAccount.fetch_all_for_owner_and_token(
context, wallet.address, wrapped_sol
)

View File

@ -74,10 +74,6 @@ try:
context, wallet.address, group, args.account_address
)
market_stub = context.market_lookup.find_by_symbol(args.market)
if market_stub is None:
raise Exception(f"Could not find serum market {args.market}")
market_operations = mango.operations(
context, wallet, account, args.market, args.dry_run
)

View File

@ -1,31 +0,0 @@
#!/usr/bin/env python3
import argparse
import logging
import os
import os.path
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import mango # nopep8
# We explicitly want argument parsing to be outside the main try-except block because some arguments
# (like --help) will cause an exit, which our except: block traps.
parser = argparse.ArgumentParser(
description="Run the Transaction Scout to display information about a specific transaction."
)
mango.ContextBuilder.add_command_line_parameters(parser)
parser.add_argument(
"--signature",
type=str,
required=True,
help="The signature of the transaction to look up",
)
args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
signature = args.signature
logging.info(f"Signature: {signature}")
report = mango.TransactionScout.load(context, signature)
mango.output(report)

View File

@ -27,11 +27,7 @@ args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
wrapped_sol: mango.Token = mango.Token.ensure(
context.instrument_lookup.find_by_symbol_or_raise("SOL")
)
wrapped_sol: mango.Token = mango.token(context, "SOL")
largest_token_account = mango.TokenAccount.fetch_largest_for_owner_and_token(
context, wallet.address, wrapped_sol
)

View File

@ -47,7 +47,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context:
context, wallet.address, group, args.account_address
)
withdrawal_value = mango.InstrumentValue(context.token(args.symbol), args.quantity)
withdrawal_value = mango.instrument_value(context, args.symbol, args.quantity)
signatures = account.withdraw(context, wallet, withdrawal_value, args.allow_borrow)
if args.wait:

View File

@ -29,10 +29,7 @@ args: argparse.Namespace = mango.parse_args(parser)
with mango.ContextBuilder.from_command_line_parameters(args) as context:
wallet = mango.Wallet.from_command_line_parameters_or_raise(args)
wrapped_sol: mango.Token = mango.Token.ensure(
context.instrument_lookup.find_by_symbol_or_raise("SOL")
)
wrapped_sol: mango.Token = mango.token(context, "SOL")
amount_to_transfer = int(args.quantity * mango.SOL_DECIMAL_DIVISOR)
signers: mango.CombinableInstructions = mango.CombinableInstructions.from_signers(

View File

@ -66,8 +66,6 @@ from .encoding import decode_binary as decode_binary
from .encoding import encode_binary as encode_binary
from .encoding import encode_key as encode_key
from .encoding import encode_int as encode_int
from .ensuremarketloaded import ensure_market_loaded as ensure_market_loaded
from .ensuremarketloaded import load_market_by_symbol as load_market_by_symbol
from .group import Group as Group
from .group import GroupSlot as GroupSlot
from .group import GroupSlotPerpMarket as GroupSlotPerpMarket
@ -170,9 +168,9 @@ from .logmessages import expand_log_messages as expand_log_messages
from .lotsizeconverter import LotSizeConverter as LotSizeConverter
from .mangoinstruction import MangoInstruction as MangoInstruction
from .lotsizeconverter import NullLotSizeConverter as NullLotSizeConverter
from .market import InventorySource as InventorySource
from .market import MarketType as MarketType
from .market import Market as Market
from .markets import InventorySource as InventorySource
from .markets import MarketType as MarketType
from .markets import Market as Market
from .marketlookup import CompoundMarketLookup as CompoundMarketLookup
from .marketlookup import MarketLookup as MarketLookup
from .marketlookup import NullMarketLookup as NullMarketLookup
@ -253,9 +251,12 @@ from .perpmarketdetails import PerpMarketDetails as PerpMarketDetails
from .perpopenorders import PerpOpenOrders as PerpOpenOrders
from .placedorder import PlacedOrder as PlacedOrder
from .placedorder import PlacedOrdersContainer as PlacedOrdersContainer
from .porcelain import market as market
from .porcelain import instruction_builder as instruction_builder
from .porcelain import instrument as instrument
from .porcelain import instrument_value as instrument_value
from .porcelain import market as market
from .porcelain import operations as operations
from .porcelain import token as token
from .publickey import encode_public_key_for_sorting as encode_public_key_for_sorting
from .reconnectingwebsocket import ReconnectingWebsocket as ReconnectingWebsocket
from .retrier import RetryWithPauses as RetryWithPauses
@ -275,9 +276,9 @@ from .spotmarket import SpotMarketOperations as SpotMarketOperations
from .spotmarket import SpotMarketStub as SpotMarketStub
from .text import indent_collection_as_str as indent_collection_as_str
from .text import indent_item_by as indent_item_by
from .token import Instrument as Instrument
from .token import SolToken as SolToken
from .token import Token as Token
from .tokens import Instrument as Instrument
from .tokens import SolToken as SolToken
from .tokens import Token as Token
from .tokenaccount import TokenAccount as TokenAccount
from .tokenbank import BankBalances as BankBalances
from .tokenbank import InterestRates as InterestRates

View File

@ -36,7 +36,7 @@ from .orders import Side
from .perpaccount import PerpAccount
from .perpopenorders import PerpOpenOrders
from .placedorder import PlacedOrder
from .token import Instrument, Token
from .tokens import Instrument, Token
from .tokenaccount import TokenAccount
from .tokenbank import TokenBank
from .version import Version

View File

@ -33,7 +33,7 @@ from .orderbookside import PerpOrderBookSide
from .perpeventqueue import PerpEvent, PerpEventQueue, UnseenPerpEventChangesTracker
from .perpmarketdetails import PerpMarketDetails
from .serumeventqueue import SerumEvent, SerumEventQueue, UnseenSerumEventChangesTracker
from .token import Instrument, Token
from .tokens import Instrument, Token
from .tokenbank import NodeBank, RootBank, TokenBank

View File

@ -23,7 +23,7 @@ from .accountinfo import AccountInfo
from .constants import SYSTEM_PROGRAM_ADDRESS
from .context import Context
from .group import Group
from .token import Token
from .tokens import Token
from .tokenaccount import TokenAccount
from .wallet import Wallet

View File

@ -20,7 +20,7 @@ import typing
from decimal import Decimal
from .output import output
from .token import Token
from .tokens import Token
# # 🥭 BalanceSheet class

View File

@ -25,7 +25,7 @@ from .context import Context
from .instrumentvalue import InstrumentValue
from .layouts import layouts
from .metadata import Metadata
from .token import Instrument, Token
from .tokens import Instrument, Token
from .version import Version

View File

@ -36,7 +36,7 @@ from .instructionreporter import InstructionReporter, CompoundInstructionReporte
from .instrumentlookup import InstrumentLookup
from .marketlookup import MarketLookup
from .text import indent_collection_as_str, indent_item_by
from .token import Instrument, Token
from .tokens import Instrument, Token
# # 🥭 Context class

View File

@ -1,58 +0,0 @@
# # ⚠ 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)
from .context import Context
from .group import Group
from .loadedmarket import LoadedMarket
from .market import Market
from .perpmarket import PerpMarketStub
from .serummarket import SerumMarketStub
from .spotmarket import SpotMarketStub
# # 🥭 ensure_market_loaded function
#
# This function ensures that a `Market` is 'loaded' and not a 'stub'. Stubs are handy for laoding in
# bulk, for instance in a market lookup, but real processing usually requires a fully loaded `Market`.
#
# This function simplifies turning a stub into a fully-loaded, usable market.
#
def ensure_market_loaded(context: Context, market: Market) -> LoadedMarket:
if isinstance(market, LoadedMarket):
return market
elif isinstance(market, SerumMarketStub):
return market.load(context)
elif isinstance(market, SpotMarketStub):
group: Group = Group.load(context, market.group_address)
return market.load(context, group)
elif isinstance(market, PerpMarketStub):
group = Group.load(context, market.group_address)
return market.load(context, group)
raise Exception(f"Market {market} could not be loaded.")
# # 🥭 load_market_by_symbol
#
# This function takes a `Context` and a market symbol string (like "ETH/USDC") and returns a loaded market. It
# throws if anything goes wrong rather than return None.
#
def load_market_by_symbol(context: Context, symbol: str) -> LoadedMarket:
market = context.market_lookup.find_by_symbol(symbol)
if market is None:
raise Exception(f"Could not find market {symbol}")
return ensure_market_loaded(context, market)

View File

@ -30,7 +30,7 @@ from .layouts import layouts
from .lotsizeconverter import LotSizeConverter, RaisingLotSizeConverter
from .marketlookup import MarketLookup
from .metadata import Metadata
from .token import Instrument, Token
from .tokens import Instrument, Token
from .tokenbank import TokenBank
from .version import Version

View File

@ -20,11 +20,11 @@ from solana.publickey import PublicKey
from .constants import MangoConstants
from .instrumentlookup import InstrumentLookup
from .market import Market
from .markets import Market
from .marketlookup import MarketLookup
from .perpmarket import PerpMarketStub
from .spotmarket import SpotMarketStub
from .token import Instrument, Token
from .tokens import Instrument, Token
class IdsJsonMarketType(enum.Enum):

View File

@ -56,7 +56,7 @@ from .orders import Order, OrderType, Side
from .perpmarketdetails import PerpMarketDetails
# from .spotmarket import SpotMarket
from .token import Token
from .tokens import Token
from .tokenaccount import TokenAccount
from .tokenbank import TokenBank, NodeBank, RootBank
from .wallet import Wallet

View File

@ -23,7 +23,7 @@ from decimal import Decimal
from solana.publickey import PublicKey
from .constants import DATA_PATH, MangoConstants
from .token import Instrument, Token
from .tokens import Instrument, Token
# # 🥭 InstrumentLookup class

View File

@ -24,7 +24,7 @@ from solana.rpc.types import TokenAccountOpts
from .context import Context
from .output import output
from .token import Instrument, Token
from .tokens import Instrument, Token
def _decimal_from_number(value: numbers.Number) -> Decimal:

View File

@ -23,7 +23,7 @@ from .account import Account
from .cache import Cache
from .group import Group
from .instrumentvalue import InstrumentValue
from .market import InventorySource, Market
from .markets import InventorySource, Market
from .openorders import OpenOrders
from .watcher import Watcher

View File

@ -21,10 +21,10 @@ from solana.publickey import PublicKey
from .accountinfo import AccountInfo
from .context import Context
from .lotsizeconverter import LotSizeConverter
from .market import InventorySource, MarketType, Market
from .markets import InventorySource, MarketType, Market
from .observables import Disposable
from .orders import Order, OrderBook
from .token import Instrument, Token
from .tokens import Instrument, Token
from .websocketsubscription import (
SharedWebSocketSubscriptionManager,
WebSocketAccountSubscription,

View File

@ -1,32 +0,0 @@
# # ⚠ 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)
from .context import Context
from .ensuremarketloaded import ensure_market_loaded
from .loadedmarket import LoadedMarket
# # 🥭 load_market_by_symbol
#
# This function takes a `Context` and a market symbol string (like "ETH/USDC") and returns a loaded market. It
# throws if anything goes wrong rather than return None.
#
def load_market_by_symbol(context: Context, symbol: str) -> LoadedMarket:
market_symbol = symbol
market = context.market_lookup.find_by_symbol(market_symbol)
if market is None:
raise Exception(f"Could not find market {market_symbol}")
return ensure_market_loaded(context, market)

View File

@ -17,7 +17,7 @@ import jsons
from decimal import Decimal
from .token import Instrument
from .tokens import Instrument
# # 🥭 LotSizeConverter class

View File

@ -20,7 +20,7 @@ import typing
from solana.publickey import PublicKey
from .market import Market
from .markets import Market
# # 🥭 MarketLookup class

View File

@ -24,7 +24,7 @@ from solana.publickey import PublicKey
from ..instrumentvalue import InstrumentValue
from ..modelstate import ModelState
from ..token import Token
from ..tokens import Token
# # 🥭 ModelStateBuilder class

View File

@ -20,7 +20,6 @@ import typing
from solana.publickey import PublicKey
from ..constants import SYSTEM_PROGRAM_ADDRESS
from ..ensuremarketloaded import ensure_market_loaded
from ..modelstate import ModelState
from .modelstatebuilder import (
ModelStateBuilder,
@ -56,7 +55,7 @@ def model_state_builder_factory(
wallet: mango.Wallet,
group: mango.Group,
account: mango.Account,
market: mango.Market,
market: mango.LoadedMarket,
oracle: mango.Oracle,
) -> ModelStateBuilder:
if mode == ModelUpdateMode.WEBSOCKET:
@ -204,10 +203,9 @@ def __load_all_openorders_watchers(
for basket_token in account.base_slots:
if basket_token.spot_open_orders is not None:
spot_market_symbol: str = f"spot:{basket_token.base_instrument.symbol}/{account.shared_quote_token.symbol}"
stub = context.market_lookup.find_by_symbol(spot_market_symbol)
if stub is None:
raise Exception(f"Could not find spot market {spot_market_symbol}")
spot_market = mango.SpotMarket.ensure(ensure_market_loaded(context, stub))
spot_market = mango.SpotMarket.ensure(
mango.market(context, spot_market_symbol)
)
oo_watcher = mango.build_spot_open_orders_watcher(
context,
websocket_manager,
@ -230,7 +228,7 @@ def _websocket_model_state_builder_factory(
wallet: mango.Wallet,
group: mango.Group,
account: mango.Account,
market: mango.Market,
market: mango.LoadedMarket,
oracle: mango.Oracle,
) -> ModelStateBuilder:
group_watcher = mango.build_group_watcher(
@ -251,7 +249,6 @@ def _websocket_model_state_builder_factory(
disposer.add_disposable(price_disposable)
health_check.add("price_subscription", price_feed)
market = mango.ensure_market_loaded(context, market)
if mango.SerumMarket.isa(market):
serum_market = mango.SerumMarket.ensure(market)
order_owner: PublicKey = (

View File

@ -21,16 +21,12 @@ import typing
from decimal import Decimal
from solana.publickey import PublicKey
from .accountinfo import AccountInfo
from .combinableinstructions import CombinableInstructions
from .constants import SYSTEM_PROGRAM_ADDRESS
from .context import Context
from .loadedmarket import Event, FillEvent, LoadedMarket
from .lotsizeconverter import LotSizeConverter, NullLotSizeConverter
from .market import InventorySource
from .observables import Disposable
from .loadedmarket import LoadedMarket
from .lotsizeconverter import NullLotSizeConverter
from .markets import InventorySource
from .orders import Order, OrderBook, OrderType, Side
from .token import Instrument, Token
# # 🥭 MarketOperations
@ -126,66 +122,10 @@ class MarketOperations(metaclass=abc.ABCMeta):
def symbol(self) -> str:
return self.market.symbol
@property
def program_address(self) -> PublicKey:
return self.market.program_address
@property
def address(self) -> PublicKey:
return self.market.address
@property
def inventory_source(self) -> InventorySource:
return self.market.inventory_source
@property
def base(self) -> Instrument:
return self.market.base
@property
def quote(self) -> Token:
return self.market.quote
@property
def lot_size_converter(self) -> LotSizeConverter:
return self.market.lot_size_converter
@property
def bids_address(self) -> PublicKey:
return self.market.bids_address
@property
def asks_address(self) -> PublicKey:
return self.market.asks_address
def parse_account_info_to_orders(
self, account_info: AccountInfo
) -> typing.Sequence[Order]:
return self.market.parse_account_info_to_orders(account_info)
def parse_account_infos_to_orderbook(
self, bids_account_info: AccountInfo, asks_account_info: AccountInfo
) -> OrderBook:
return self.market.parse_account_infos_to_orderbook(
bids_account_info, asks_account_info
)
def fetch_orderbook(self, context: Context) -> OrderBook:
[bids_info, asks_info] = AccountInfo.load_multiple(
context, [self.bids_address, self.asks_address]
)
return self.parse_account_infos_to_orderbook(bids_info, asks_info)
def on_fill(
self, context: Context, handler: typing.Callable[[FillEvent], None]
) -> Disposable:
return self.market.on_fill(context, handler)
def on_event(
self, context: Context, handler: typing.Callable[[Event], None]
) -> Disposable:
return self.market.on_event(context, handler)
@abc.abstractmethod
def cancel_order(
self, order: Order, ok_if_missing: bool = False

View File

@ -21,7 +21,7 @@ import logging
from solana.publickey import PublicKey
from .lotsizeconverter import LotSizeConverter
from .token import Instrument, Token
from .tokens import Instrument, Token
class MarketType(enum.Enum):

View File

@ -23,7 +23,7 @@ from solana.publickey import PublicKey
from .account import Account
from .group import Group
from .inventory import Inventory
from .market import Market
from .markets import Market
from .oracle import Price
from .orders import Order, OrderBook
from .placedorder import PlacedOrdersContainer

View File

@ -23,7 +23,7 @@ from datetime import datetime
from decimal import Decimal
from .context import Context
from .market import Market
from .markets import Market
# # 🥭 Oracles

View File

@ -26,7 +26,7 @@ from rx.subject.subject import Subject
from ...context import Context
from ...datetimes import utc_now
from ...market import Market
from ...markets import Market
from ...observables import Disposable, DisposeWrapper
from ...oracle import (
Oracle,

View File

@ -22,9 +22,8 @@ from decimal import Decimal
from ...context import Context
from ...datetimes import utc_now
from ...ensuremarketloaded import ensure_market_loaded
from ...loadedmarket import LoadedMarket
from ...market import Market
from ...markets import Market
from ...observables import observable_pipeline_error_reporter
from ...oracle import (
Oracle,
@ -34,6 +33,7 @@ from ...oracle import (
SupportedOracleFeature,
)
from ...orders import OrderBook
from ...porcelain import market as porcelain_market
# # 🥭 Market
@ -118,7 +118,7 @@ class MarketOracleProvider(OracleProvider):
def oracle_for_market(
self, context: Context, market: Market
) -> typing.Optional[Oracle]:
loaded_market: LoadedMarket = ensure_market_loaded(context, market)
loaded_market: LoadedMarket = porcelain_market(context, market.symbol)
return MarketOracle(loaded_market)
def all_available_symbols(self, context: Context) -> typing.Sequence[str]:

View File

@ -25,7 +25,7 @@ from solana.publickey import PublicKey
from ...accountinfo import AccountInfo
from ...context import Context
from ...datetimes import utc_now
from ...market import Market
from ...markets import Market
from ...observables import observable_pipeline_error_reporter
from ...oracle import (
Oracle,

View File

@ -24,8 +24,8 @@ from solana.publickey import PublicKey
from ...cache import Cache
from ...context import Context
from ...datetimes import utc_now
from ...ensuremarketloaded import ensure_market_loaded
from ...market import Market
from ...loadedmarket import LoadedMarket
from ...markets import Market
from ...observables import observable_pipeline_error_reporter
from ...oracle import (
Oracle,
@ -35,6 +35,7 @@ from ...oracle import (
SupportedOracleFeature,
)
from ...perpmarket import PerpMarket
from ...porcelain import market as porcelain_market
from ...spotmarket import SpotMarket
@ -117,7 +118,7 @@ class StubOracleProvider(OracleProvider):
def oracle_for_market(
self, context: Context, market: Market
) -> typing.Optional[Oracle]:
loaded_market: Market = ensure_market_loaded(context, market)
loaded_market: LoadedMarket = porcelain_market(context, market.symbol)
if SpotMarket.isa(loaded_market):
spot_market = SpotMarket.ensure(loaded_market)
spot_index: int = spot_market.group.slot_by_spot_market_address(

View File

@ -21,7 +21,7 @@ from .cache import PerpMarketCache
from .instrumentvalue import InstrumentValue
from .lotsizeconverter import LotSizeConverter
from .perpopenorders import PerpOpenOrders
from .token import Instrument, Token
from .tokens import Instrument, Token
# # 🥭 PerpAccount class

View File

@ -38,7 +38,7 @@ from .instructions import (
)
from .loadedmarket import LoadedMarket
from .lotsizeconverter import LotSizeConverter, RaisingLotSizeConverter
from .market import InventorySource, MarketType, Market
from .markets import InventorySource, MarketType, Market
from .marketoperations import MarketInstructionBuilder, MarketOperations
from .observables import Disposable
from .orderbookside import PerpOrderBookSide
@ -51,7 +51,7 @@ from .perpeventqueue import (
)
from .perpmarketdetails import PerpMarketDetails
from .publickey import encode_public_key_for_sorting
from .token import Instrument, Token
from .tokens import Instrument, Token
from .tokenbank import TokenBank
from .wallet import Wallet
from .websocketsubscription import (
@ -418,6 +418,14 @@ class PerpMarketOperations(MarketOperations):
)
self.account: Account = account
@staticmethod
def ensure(market_ops: MarketOperations) -> "PerpMarketOperations":
if not isinstance(market_ops, PerpMarketOperations):
raise Exception(
f"MarketOperations for {market_ops.symbol} is not a PerpMarketOperations"
)
return market_ops
@property
def perp_market(self) -> PerpMarket:
return self.market_instruction_builder.perp_market

View File

@ -27,7 +27,7 @@ from .group import GroupSlot, Group
from .instrumentvalue import InstrumentValue
from .layouts import layouts
from .metadata import Metadata
from .token import Instrument, Token
from .tokens import Instrument, Token
from .tokenbank import TokenBank
from .version import Version

View File

@ -13,9 +13,12 @@
# [Github](https://github.com/blockworks-foundation)
# [Email](mailto:hello@blockworks.foundation)
from decimal import Decimal
from .account import Account
from .context import Context
from .group import Group
from .instrumentvalue import InstrumentValue
from .loadedmarket import LoadedMarket
from .marketoperations import (
MarketInstructionBuilder,
@ -41,10 +44,45 @@ from .spotmarket import (
SpotMarketInstructionBuilder,
SpotMarketOperations,
)
from .tokens import Instrument, Token
from .wallet import Wallet
# # 🥭 load_market
# # 🥭 instrument
#
# This function takes a `Context` and an instrument symbol string (like "ETH") and returns a
# properly loaded `Instrument` object. It throws if anything goes wrong rather than return None.
#
# An Instrument can represent a Perp or an SPL token.
#
def instrument(context: Context, symbol: str) -> Instrument:
return context.instrument(symbol)
# # 🥭 token
#
# This function takes a `Context` and a token symbol string (like "ETH") and returns a
# properly loaded `Token` object. It throws if anything goes wrong rather than return None.
#
# An Token can only represent an SPL token. It cannot represent a Perp.
#
def token(context: Context, symbol: str) -> Token:
return context.token(symbol)
# # 🥭 instrument_value
#
# This function takes a `Context` and an instrument symbol string (like "ETH") and returns a
# properly loaded `Instrument` object. It throws if anything goes wrong rather than return None.
#
# An Instrument can represent a Perp or an SPL token.
#
def instrument_value(context: Context, symbol: str, value: Decimal) -> InstrumentValue:
ins = context.instrument(symbol)
return InstrumentValue(ins, value)
# # 🥭 market
#
# This function takes a `Context` and a market symbol string (like "ETH/USDC") and returns a
# properly loaded market. It throws if anything goes wrong rather than return None.

View File

@ -33,14 +33,14 @@ from .instructions import (
)
from .loadedmarket import LoadedMarket
from .lotsizeconverter import LotSizeConverter, RaisingLotSizeConverter
from .market import InventorySource, Market, MarketType
from .markets import InventorySource, Market, MarketType
from .marketoperations import MarketInstructionBuilder, MarketOperations
from .openorders import OpenOrders
from .observables import Disposable
from .orders import Order, OrderBook, Side
from .publickey import encode_public_key_for_sorting
from .serumeventqueue import SerumEvent, SerumEventQueue, UnseenSerumEventChangesTracker
from .token import Instrument, Token
from .tokens import Instrument, Token
from .tokenaccount import TokenAccount
from .wallet import Wallet
from .websocketsubscription import (
@ -411,6 +411,14 @@ class SerumMarketOperations(MarketOperations):
market_instruction_builder
)
@staticmethod
def ensure(market_ops: MarketOperations) -> "SerumMarketOperations":
if not isinstance(market_ops, SerumMarketOperations):
raise Exception(
f"MarketOperations for {market_ops.symbol} is not a SerumMarketOperations"
)
return market_ops
@property
def serum_market(self) -> SerumMarket:
return self.market_instruction_builder.serum_market

View File

@ -20,10 +20,10 @@ import typing
from decimal import Decimal
from solana.publickey import PublicKey
from .market import Market
from .markets import Market
from .marketlookup import MarketLookup
from .serummarket import SerumMarketStub
from .token import Instrument, Token
from .tokens import Instrument, Token
# # 🥭 SerumMarketLookup class

View File

@ -37,13 +37,13 @@ from .instructions import (
)
from .loadedmarket import LoadedMarket
from .lotsizeconverter import LotSizeConverter, RaisingLotSizeConverter
from .market import InventorySource, MarketType, Market
from .markets import InventorySource, MarketType, Market
from .marketoperations import MarketInstructionBuilder, MarketOperations
from .observables import Disposable
from .orders import Order, OrderBook
from .publickey import encode_public_key_for_sorting
from .serumeventqueue import SerumEvent, SerumEventQueue, UnseenSerumEventChangesTracker
from .token import Token
from .tokens import Token
from .wallet import Wallet
from .websocketsubscription import (
IndividualWebSocketSubscriptionManager,
@ -440,6 +440,14 @@ class SpotMarketOperations(MarketOperations):
PublicKey
] = self.account.spot_open_orders_by_index[self.market_index]
@staticmethod
def ensure(market_ops: MarketOperations) -> "SpotMarketOperations":
if not isinstance(market_ops, SpotMarketOperations):
raise Exception(
f"MarketOperations for {market_ops.symbol} is not a SpotMarketOperations"
)
return market_ops
@property
def spot_market(self) -> SpotMarket:
return self.market_instruction_builder.spot_market

View File

@ -30,7 +30,7 @@ from .context import Context
from .instrumentlookup import InstrumentLookup
from .instrumentvalue import InstrumentValue
from .layouts import layouts
from .token import Instrument, Token
from .tokens import Instrument, Token
from .version import Version
from .wallet import Wallet

View File

@ -28,7 +28,7 @@ from .context import Context
from .instrumentlookup import InstrumentLookup
from .layouts import layouts
from .metadata import Metadata
from .token import Instrument, Token
from .tokens import Instrument, Token
from .version import Version

View File

@ -25,7 +25,7 @@ from .context import Context
from .group import Group
from .marketoperations import MarketOperations
from .porcelain import operations
from .token import Instrument, Token
from .tokens import Instrument, Token
from .instrumentvalue import InstrumentValue
from .wallet import Wallet

View File

@ -31,7 +31,7 @@ from .instructions import build_create_serum_open_orders_instructions
from .instrumentvalue import InstrumentValue
from .inventory import Inventory
from .loadedmarket import LoadedMarket
from .market import Market, InventorySource
from .markets import Market, InventorySource
from .modelstate import EventQueue
from .observables import Disposable, LatestItemObserverSubscriber
from .openorders import OpenOrders
@ -46,7 +46,7 @@ from .serumeventqueue import SerumEventQueue
from .serummarket import SerumMarket
from .spotmarket import SpotMarket, SpotMarketInstructionBuilder, SpotMarketOperations
from .tokenaccount import TokenAccount
from .token import Instrument, Token
from .tokens import Instrument, Token
from .wallet import Wallet
from .watcher import Watcher, LamdaUpdateWatcher
from .websocketsubscription import (