Initial commit: 首次建仓,建立目录结构

This commit is contained in:
FXY
2026-06-11 23:49:54 +08:00
commit 4038a476b5
9396 changed files with 2372905 additions and 0 deletions

View File

@ -0,0 +1,347 @@
# -*- coding: utf-8 -*-
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
import ccxt.async_support
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolBySide
from ccxt.base.types import Any, Int, OrderBook, Position, Strings, Trade
from ccxt.async_support.base.ws.client import Client
from typing import List
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
class aftermath(ccxt.async_support.aftermath):
def describe(self) -> Any:
return self.deep_extend(super(aftermath, self).describe(), {
'has': {
'ws': True,
'watchBalance': False,
'watchMyTrades': False,
'watchOHLCV': False,
'watchOrderBook': True,
'watchOrders': False,
'watchTicker': False,
'watchTickers': False,
'watchBidsAsks': False,
'watchTrades': True,
'watchTradesForSymbols': False,
'watchPositions': True,
},
'urls': {
'api': {
'ws': {
'swap': 'wss://aftermath.finance/iperps-api/ccxt/stream',
},
},
'test': {
'ws': {
'swap': 'wss://testnet.aftermath.finance/iperps-api/ccxt/stream',
},
},
},
'options': {
'tradesLimit': 1000,
'ordersLimit': 1000,
'watchPositions': {
'fetchPositionsSnapshot': True, # or False
'awaitPositionsSnapshot': True, # whether to wait for the positions snapshot before providing updates
},
},
'streaming': {
'keepAlive': 59000,
},
'exceptions': {
},
})
async def watch_public(self, suffix, messageHash, message):
url = self.urls['api']['ws']['swap'] + '/' + suffix
return await self.watch(url, messageHash, self.json(message), messageHash, message)
async def watch_public_multiple(self, suffix, messageHashes, message):
url = self.urls['api']['ws']['swap'] + '/' + suffix
return await self.watch_multiple(url, messageHashes, self.json(message), messageHashes, message)
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
"""
watches information on multiple trades made in a market
https://testnet.aftermath.finance/docs/#/CCXT/service%3A%3Ahandlers%3A%3Accxt%3A%3Astream%3A%3Atrades
:param str symbol: unified market symbol of the market trades were made in
:param int [since]: the earliest time in ms to fetch trades for
:param int [limit]: the maximum number of trade structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/?id=trade-structure>`
"""
await self.load_markets()
market = self.market(symbol)
symbol = market['symbol']
topic = market['id'] + '@trade'
request: dict = {
'chId': market['id'],
}
message = self.extend(request, params)
trades = await self.watch_public('trades', topic, message)
if self.newUpdates:
limit = trades.getLimit(market['symbol'], limit)
return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
def handle_trade(self, client: Client, message):
#
# {
# "amount": 0.1,
# "cost": 0.1,
# "datetime": "string",
# "fee": null,
# "id": "string",
# "order": "string",
# "price": 0.1,
# "side": null,
# "symbol": "string",
# "takerOrMaker": null,
# "timestamp": null,
# "type": "string"
# }
#
trade = self.parse_trade(message)
symbol = trade['symbol']
market = self.market(symbol)
if not (symbol in self.trades):
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
stored = ArrayCache(limit)
self.trades[symbol] = stored
messageHash = market['id'] + '@trade'
trades = self.trades[symbol]
trades.append(trade)
self.trades[symbol] = trades
client.resolve(trades, messageHash)
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
"""
https://testnet.aftermath.finance/docs/#/CCXT/service%3A%3Ahandlers%3A%3Accxt%3A%3Astream%3A%3Aorderbook
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
:param str symbol: unified symbol of the market to fetch the order book for
:param int [limit]: the maximum amount of order book entries to return.
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/?id=order-book-structure>` indexed by market symbols
"""
await self.load_markets()
market = self.market(symbol)
symbol = market['symbol']
topic = market['id'] + '@orderbook'
request: dict = {
'chId': market['id'],
}
message = self.extend(request, params)
orderbook = await self.watch_public('orderbook', topic, message)
return orderbook.limit()
def handle_order_book(self, client: Client, message):
#
# {
# "asks": [
# []
# ],
# "bids": [
# []
# ],
# "datetime": "string",
# "nonce": 9007199254740991,
# "symbol": "string",
# "timestamp": 9007199254740991
# }
#
symbol = self.safe_string(message, 'symbol')
market = self.market(symbol)
topic = market['id'] + '@orderbook'
if not (symbol in self.orderbooks):
defaultLimit = self.safe_integer(self.options, 'watchOrderBookLimit', 1000)
subscription = client.subscriptions[topic]
limit = self.safe_integer(subscription, 'limit', defaultLimit)
self.orderbooks[symbol] = self.order_book({}, limit)
subscription['limit'] = limit
self.spawn(self.fetch_order_book_snapshot, client, message, subscription)
else:
orderbook = self.orderbooks[symbol]
prevNonce = self.safe_integer(orderbook, 'nonce')
nonce = self.safe_integer(message, 'nonce')
if nonce == (prevNonce + 1):
self.handle_order_book_message(client, message, orderbook)
client.resolve(orderbook, topic)
async def fetch_order_book_snapshot(self, client, message, subscription):
symbol = self.safe_string(message, 'symbol')
market = self.market(symbol)
messageHash = market['id'] + '@orderbook'
try:
defaultLimit = self.safe_integer(self.options, 'watchOrderBookLimit', 1000)
limit = self.safe_integer(subscription, 'limit', defaultLimit)
params = self.safe_dict(subscription, 'params')
snapshot = await self.fetch_rest_order_book_safe(symbol, limit, params)
if self.safe_value(self.orderbooks, symbol) is None:
# if the orderbook is dropped before the snapshot is received
return
orderbook = self.orderbooks[symbol]
orderbook.reset(snapshot)
self.orderbooks[symbol] = orderbook
client.resolve(orderbook, messageHash)
except Exception as e:
del client.subscriptions[messageHash]
client.reject(e, messageHash)
def handle_order_book_message(self, client: Client, message, orderbook):
self.handle_deltas(orderbook['asks'], self.safe_value(message, 'asks', []))
self.handle_deltas(orderbook['bids'], self.safe_value(message, 'bids', []))
timestamp = self.safe_integer(message, 'timestamp')
nonce = self.safe_integer(message, 'nonce')
orderbook['timestamp'] = timestamp
orderbook['datetime'] = self.iso8601(timestamp)
orderbook['nonce'] = nonce
return orderbook
def handle_delta(self, bookside, delta):
price = self.safe_float_2(delta, 'price', 0)
amount = self.safe_float_2(delta, 'quantity', 1)
bookside.store(price, amount)
def handle_deltas(self, bookside, deltas):
for i in range(0, len(deltas)):
self.handle_delta(bookside, deltas[i])
async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
"""
https://testnet.aftermath.finance/docs/#/CCXT/service%3A%3Ahandlers%3A%3Accxt%3A%3Astream%3A%3Apositions
watch all open positions
:param str[]|None symbols: list of unified market symbols
:param int [since]: the earliest time in ms to fetch positions for
:param int [limit]: the maximum number of position structures to retrieve
:param dict params: extra parameters specific to the exchange API endpoint
:param int [params.accountNumber]: account number to query orders for, required
:returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
"""
await self.load_markets()
messageHashes = []
symbols = self.market_symbols(symbols)
if not self.is_empty(symbols):
for i in range(0, len(symbols)):
symbol = symbols[i]
messageHashes.append('positions::' + symbol)
else:
messageHashes.append('positions')
accountNumber = self.safe_number(params, 'accountNumber')
request = {
'accountNumber': accountNumber,
}
message = self.extend(request, params)
suffix = 'positions'
url = self.urls['api']['ws']['swap'] + '/' + suffix
client = self.client(url)
self.set_positions_cache(client, symbols, params)
fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
awaitPositionsSnapshot = self.handle_option('watchPositions', 'awaitPositionsSnapshot', True)
if fetchPositionsSnapshot and awaitPositionsSnapshot and self.positions is None:
snapshot = await client.future('fetchPositionsSnapshot')
return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True)
newPositions = await self.watch_public_multiple(suffix, messageHashes, message)
if self.newUpdates:
return newPositions
return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit, True)
def set_positions_cache(self, client: Client, symbols: Strings = None, params: dict = {}):
fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', False)
if fetchPositionsSnapshot:
messageHash = 'fetchPositionsSnapshot'
if not (messageHash in client.futures):
client.future(messageHash)
self.spawn(self.load_positions_snapshot, client, messageHash, symbols, params)
else:
self.positions = ArrayCacheBySymbolBySide()
async def load_positions_snapshot(self, client, messageHash, symbols, params):
positions = await self.fetch_positions(symbols, params)
self.positions = ArrayCacheBySymbolBySide()
cache = self.positions
for i in range(0, len(positions)):
position = positions[i]
cache.append(position)
# don't remove the future from the .futures cache
future = client.futures[messageHash]
future.resolve(cache)
client.resolve(cache, 'positions')
def handle_positions(self, client, message):
#
# {
# "collateral": 0.1,
# "contractSize": 0.1,
# "contracts": 0.1,
# "datetime": "string",
# "entryPrice": 0.1,
# "id": "0x895037c09dd1025a136b5a5789c4ea2481176adf4c3b0c3521d5d2039bdfc3ba:123",
# "initialMargin": 0.1,
# "initialMarginPercentage": 0.1,
# "leverage": 0.1,
# "liquidationPrice": 0.1,
# "maintenanceMargin": 0.1,
# "maintenanceMarginPercentage": 0.1,
# "marginMode": "cross",
# "marginRatio": 0.1,
# "notional": 0.1,
# "side": "long",
# "symbol": "BTC/USD:USDC",
# "timestamp": 9007199254740991,
# "unrealizedPnl": 0.1
# }
#
if self.positions is None:
self.positions = ArrayCacheBySymbolBySide()
cache = self.positions
symbol = self.safe_string(message, 'symbol')
market = self.safe_market(symbol)
position = self.parse_position(message, market)
cache.append(position)
messageHash = 'positions::' + market['symbol']
client.resolve(position, messageHash)
client.resolve([position], 'positions')
def handle_error_message(self, client: Client, message):
#
# User error: Expected Message::Text from client, got Ping(b\"\")
#
if isinstance(message, str):
if message.find('error') >= 0:
try:
feedback = self.id + ' ' + message
self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
raise ExchangeError(message)
except Exception as error:
if isinstance(error, AuthenticationError):
messageHash = 'authenticated'
client.reject(error, messageHash)
if messageHash in client.subscriptions:
del client.subscriptions[messageHash]
else:
client.reject(error)
return True
return False
def handle_message(self, client: Client, message):
if self.handle_error_message(client, message):
return
# methods: Dict = {
# 'trade': self.handle_trade,
# }
if 'asks' in message:
self.handle_order_book(client, message)
elif 'notional' in message:
self.handle_positions(client, message)
else:
self.handle_trade(client, message)