Mango Markets
Searchโ€ฆ
Client Libraries
The following client libraries are currently independently maintained by the community:
In an attempt to create uniformity we have documented the major functions, which are available across all libraries.

Package Install

Add your preferred library to your project.
TypeScript
C#
Python
Using npm:
1
npm install @blockworks-foundation/mango-client
Copied!
Using yarn:
1
yarn add @blockworks-foundation/mango-client
Copied!
Solnet.Mango can be installed via the Nuget Package Manager or by using any of the following command lines.
1
Install-Package Solnet.Mango -Version 5.0.1 // Package Manager
2
dotnet add package Solnet.Mango --version 5.0.1 // .NET CLI
3
<PackageReference Include="Solnet.Mango" Version="5.0.1" /> // PackageReference
4
paket add Solnet.Mango --version 5.0.1 // Paket CLI
5
#r "nuget: Solnet.Mango, 5.0.1" // Script & Interactive
Copied!
1
pip install mango-explorer
Copied!

Subscribe to an Order Book

To get the order book you need to retrieve the bids and asks independently. Each side of the order book has a max capacity of 512 orders. When the 512 capacity is reached, orders that are the furthest away from the top will be removed when a new order is added and the Out Event is fired when an order is removed. Orders can be set to expire using the Time-In-Force
TypeScript
C#
Python
1
import {
2
BookSide,
3
BookSideLayout,
4
Config,
5
getMarketByBaseSymbolAndKind,
6
GroupConfig,
7
MangoClient,
8
} from '../src';
9
import { Commitment, Connection } from '@solana/web3.js';
10
import configFile from '../src/ids.json';
11
โ€‹
12
async function subscribeToOrderbook() {
13
// setup client
14
const config = new Config(configFile);
15
const groupConfig = config.getGroupWithName('mainnet.1') as GroupConfig;
16
const connection = new Connection(
17
config.cluster_urls[groupConfig.cluster],
18
'processed' as Commitment,
19
);
20
const client = new MangoClient(connection, groupConfig.mangoProgramId);
21
โ€‹
22
// load group & market
23
const perpMarketConfig = getMarketByBaseSymbolAndKind(
24
groupConfig,
25
'BTC',
26
'perp',
27
);
28
const mangoGroup = await client.getMangoGroup(groupConfig.publicKey);
29
const perpMarket = await mangoGroup.loadPerpMarket(
30
connection,
31
perpMarketConfig.marketIndex,
32
perpMarketConfig.baseDecimals,
33
perpMarketConfig.quoteDecimals,
34
);
35
โ€‹
36
// subscribe to bids
37
connection.onAccountChange(perpMarketConfig.bidsKey, (accountInfo) => {
38
const bids = new BookSide(
39
perpMarketConfig.bidsKey,
40
perpMarket,
41
BookSideLayout.decode(accountInfo.data),
42
);
43
โ€‹
44
// print L2 orderbook data
45
for (const [price, size] of bids.getL2(20)) {
46
console.log(price, size);
47
}
48
โ€‹
49
// print L3 orderbook data
50
for (const order of bids) {
51
console.log(
52
order.owner.toBase58(),
53
order.orderId.toString('hex'),
54
order.price,
55
order.size,
56
order.side, // 'buy' or 'sell'
57
);
58
}
59
});
60
}
61
โ€‹
62
subscribeToOrderbook();
Copied!
โ€‹
1
//Mango Client
2
IRpcClient rpcClient = Solnet.Rpc.ClientFactory.GetClient(Cluster.MainNet);
3
IStreamingRpcClient streamingRpcClient = ClientFactory.GetStreamingClient(Cluster.MainNet);
4
IMangoClient mangoClient = Solnet.Mango.ClientFactory.GetClient(rpcClient, streamingRpcClient);
5
โ€‹
6
//Connect Streaming Client
7
await mangoClient.StreamingRpcClient.ConnectAsync();
8
โ€‹
9
//Market
10
AccountResultWrapper<PerpMarket> perpMarket = await mangoClient.GetPerpMarketAsync("DtEcjPLyD4YtTBB4q8xwFZ9q49W89xZCZtJyrGebi5t8"); // BTC-PERP
11
โ€‹
12
//Subscribe to each side of the order book
13
await mangoClient.SubscribeOrderBookSideAsync((_, side, _) =>
14
{
15
List<OpenOrder> bids = side.GetOrders();
16
}, perpMarket.ParsedResult.Bids, Commitment.Processed);
17
โ€‹
18
await mangoClient.SubscribeOrderBookSideAsync((_, side, _) =>
19
{
20
List<OpenOrder> asks = side.GetOrders();
21
}, perpMarket.ParsedResult.Asks, Commitment.Processed);
Copied!
OpenOrder model:
1
public BigInteger OrderId; //The order id.
2
public ulong ClientOrderId; // The client's order id.
3
public int OrderIndex; // The index of the order within the lists of order data in the Mango account
4
public long RawPrice; //The raw value for the price of the order.
5
public long RawQuantity; //The raw value for the quantity of the order.
6
public PublicKey Owner; //The owner of this order.
7
public ulong Timestamp; //The timestamp.
8
public ulong ExpiryTimestamp; //Timestamp of expiry.
9
public byte TimeInForce; //The time in force.
10
public PerpOrderType OrderType; //The order type.
Copied!
This code will connect to the devnet cluster and will print out the latest orderbook every time the orderbook changes, and will exit after 60 seconds.
1
import datetime
2
import mango
3
import time
4
โ€‹
5
with mango.ContextBuilder.build(cluster_name="devnet") as context:
6
market = mango.market(context, "BTC-PERP")
7
subscription = market.on_orderbook_change(context, lambda ob: print("\n", datetime.datetime.now(), "\n", ob))
8
โ€‹
9
time.sleep(60)
10
โ€‹
11
subscription.dispose()
12
โ€‹
13
print("Example complete.")
Copied!

Get an Order Book snapshot

You can also retrieve a snapshot of the order book.
TypeScript
C#
Python
1
import {
2
Config,
3
getMarketByBaseSymbolAndKind,
4
GroupConfig,
5
MangoClient,
6
} from '../src';
7
import { Commitment, Connection } from '@solana/web3.js';
8
import configFile from '../src/ids.json';
9
โ€‹
10
async function snapshotOrderbook() {
11
// setup client
12
const config = new Config(configFile);
13
const groupConfig = config.getGroupWithName('mainnet.1') as GroupConfig;
14
const connection = new Connection(
15
config.cluster_urls[groupConfig.cluster],
16
'processed' as Commitment,
17
);
18
const client = new MangoClient(connection, groupConfig.mangoProgramId);
19
โ€‹
20
// load group & market
21
const perpMarketConfig = getMarketByBaseSymbolAndKind(
22
groupConfig,
23
'BTC',
24
'perp',
25
);
26
const mangoGroup = await client.getMangoGroup(groupConfig.publicKey);
27
const perpMarket = await mangoGroup.loadPerpMarket(
28
connection,
29
perpMarketConfig.marketIndex,
30
perpMarketConfig.baseDecimals,
31
perpMarketConfig.quoteDecimals,
32
);
33
โ€‹
34
// load bids
35
const bids = await perpMarket.loadBids(connection);
36
โ€‹
37
// print L2 orderbook data
38
for (const [price, size] of bids.getL2(20)) {
39
console.log(price, size);
40
}
41
โ€‹
42
// print L3 orderbook data
43
for (const order of bids) {
44
console.log(
45
order.owner.toBase58(),
46
order.orderId.toString('hex'),
47
order.price,
48
order.size,
49
order.side,
50
);
51
}
52
}
53
โ€‹
54
snapshotOrderbook();
Copied!
โ€‹
1
//Mango Client
2
IRpcClient rpcClient = Solnet.Rpc.ClientFactory.GetClient(Cluster.MainNet);
3
IStreamingRpcClient streamingRpcClient = ClientFactory.GetStreamingClient(Cluster.MainNet);
4
IMangoClient mangoClient = Solnet.Mango.ClientFactory.GetClient(rpcClient, streamingRpcClient);
5
โ€‹
6
//Market
7
AccountResultWrapper<PerpMarket> perpMarket = await mangoClient.GetPerpMarketAsync("DtEcjPLyD4YtTBB4q8xwFZ9q49W89xZCZtJyrGebi5t8"); // BTC-PERP
8
โ€‹
9
//Request order book sides
10
AccountResultWrapper<OrderBookSide> bidsRequest = await mangoClient.GetOrderBookSideAsync(perpMarket.ParsedResult.Bids, Commitment.Processed); // Bids side of the orderbook
11
AccountResultWrapper<OrderBookSide> asksRequest = await mangoClient.GetOrderBookSideAsync(perpMarket.ParsedResult.Asks, Commitment.Processed); // Asks side of the orderbook
12
โ€‹
13
List<OpenOrder> bids = bidsRequest.ParsedResult.GetOrders();
14
List<OpenOrder> asks = asksRequest.ParsedResult.GetOrders();
Copied!
This code will connect to the devnet cluster, fetch the orderbook for BTC-PERP, and print out a summary of it:
1
import mango
2
โ€‹
3
with mango.ContextBuilder.build(cluster_name="devnet") as context:
4
market = mango.market(context, "BTC-PERP")
5
print(market.fetch_orderbook(context))
Copied!

Subscribe to Market Fills

You can subscribe to a markets' event queue. When the event queue is updated, the entire queue is received. You can filter the event queue for fills and use the sequence number to filter new fills added to the queue.
TypeScript
C#
Python
1
import {
2
Config,
3
getMarketByBaseSymbolAndKind,
4
GroupConfig,
5
MangoClient,
6
PerpEventQueue,
7
PerpEventQueueLayout,
8
ZERO_BN,
9
} from '../src';
10
import { Commitment, Connection } from '@solana/web3.js';
11
import configFile from '../src/ids.json';
12
import { ParsedFillEvent } from '../src/PerpMarket';
13
โ€‹
14
async function subscribeToOrderbook() {
15
// setup client
16
const config = new Config(configFile);
17
const groupConfig = config.getGroupWithName('mainnet.1') as GroupConfig;
18
const connection = new Connection(
19
config.cluster_urls[groupConfig.cluster],
20
'processed' as Commitment,
21
);
22
const client = new MangoClient(connection, groupConfig.mangoProgramId);
23
โ€‹
24
// load group & market
25
const perpMarketConfig = getMarketByBaseSymbolAndKind(
26
groupConfig,
27
'BTC',
28
'perp',
29
);
30
const mangoGroup = await client.getMangoGroup(groupConfig.publicKey);
31
const perpMarket = await mangoGroup.loadPerpMarket(
32
connection,
33
perpMarketConfig.marketIndex,
34
perpMarketConfig.baseDecimals,
35
perpMarketConfig.quoteDecimals,
36
);
37
โ€‹
38
// subscribe to event queue
39
const lastSeenSeqNum = ZERO_BN;
40
connection.onAccountChange(perpMarketConfig.eventsKey, (accountInfo) => {
41
const queue = new PerpEventQueue(
42
PerpEventQueueLayout.decode(accountInfo.data),
43
);
44
const fills = queue
45
.eventsSince(lastSeenSeqNum)
46
.map((e) => e.fill)
47
.filter((e) => !!e)
48
.map((e) => perpMarket.parseFillEvent(e) as ParsedFillEvent);
49
โ€‹
50
for (const fill of fills) {
51
console.log(`New fill for ${fill.quantity} at ${fill.price}`);
52
}
53
});
54
}
55
โ€‹
56
subscribeToOrderbook();
Copied!
1
//Mango Client
2
IRpcClient rpcClient = ClientFactory.GetClient(Cluster.MainNet);
3
IStreamingRpcClient streamingRpcClient = ClientFactory.GetStreamingClient(Cluster.MainNet);
4
IMangoClient mangoClient = Solnet.Mango.ClientFactory.GetClient(rpcClient, streamingRpcClient);
5
โ€‹
6
//Connect Streaming Client
7
await mangoClient.StreamingRpcClient.ConnectAsync();
8
โ€‹
9
//Market and Event Queue
10
AccountResultWrapper<PerpMarket> perpMarket = await mangoClient.GetPerpMarketAsync("DtEcjPLyD4YtTBB4q8xwFZ9q49W89xZCZtJyrGebi5t8"); // BTC-PERP
11
โ€‹
12
//Subscribe the event queue
13
await mangoClient.SubscribeEventQueueAsync((_, queue, _) =>
14
{
15
foreach (Event evt in queue.Events)
16
{
17
switch (evt)
18
{
19
case FillEvent fill:
20
Console.Write(fill.Price);
21
break;
22
}
23
}
24
}, perpMarket.ParsedResult.EventQueue, Commitment.Processed);
Copied!
FillEvent model:
1
public Side TakerSide;//The side from the taker's point of view.
2
public byte MakerSlot;// The slot of the order in the maker's orders.
3
public bool MakerOut; // Whether the maker's order quantity has nothing left to fill.
4
public PublicKey Maker; // The maker's public key.
5
public BigInteger MakerOrderId; // The maker's order id.
6
public ulong MakerClientOrderId; // The maker's client order id.
7
public I80F48 MakerFee; // The maker fee.
8
public long BestInitial; // The best bid/ask at the time the maker order was placed.
9
public ulong MakerTimestamp; // Timestamp of when the maker order was placed.
10
public PublicKey Taker; // The taker's public key.
11
public BigInteger TakerOrderId; // The taker's order id.
12
public ulong TakerClientOrderId; // The taker's client order id.
13
public I80F48 TakerFee; // The taker fee.
14
public long Price; // The price of the fill.
15
public long Quantity; // The quantity that was filled.
Copied!
This code will connect to the devnet cluster and print out every fill that happens. It will exit after 60 seconds.
1
import datetime
2
import mango
3
import time
4
โ€‹
5
with mango.ContextBuilder.build(cluster_name="devnet") as context:
6
market = mango.market(context, "BTC-PERP")
7
subscription = market.on_fill(context, lambda ob: print("\n", datetime.datetime.now(), "\n", ob))
8
โ€‹
9
time.sleep(60)
10
โ€‹
11
subscription.dispose()
12
โ€‹
13
print("Example complete.")
Copied!

Get a Market fills snapshot

You can also retrieve a snapshot of a markets' event queue.
TypeScript
C#
Python
1
import {
2
Config,
3
getMarketByBaseSymbolAndKind,
4
GroupConfig,
5
MangoClient,
6
} from '../src';
7
import { Commitment, Connection } from '@solana/web3.js';
8
import configFile from '../src/ids.json';
9
โ€‹
10
async function snapshotFills() {
11
// setup client
12
const config = new Config(configFile);
13
const groupConfig = config.getGroupWithName('mainnet.1') as GroupConfig;
14
const connection = new Connection(
15
config.cluster_urls[groupConfig.cluster],
16
'processed' as Commitment,
17
);
18
const client = new MangoClient(connection, groupConfig.mangoProgramId);
19
โ€‹
20
// load group & market
21
const perpMarketConfig = getMarketByBaseSymbolAndKind(
22
groupConfig,
23
'BTC',
24
'perp',
25
);
26
const mangoGroup = await client.getMangoGroup(groupConfig.publicKey);
27
const perpMarket = await mangoGroup.loadPerpMarket(
28
connection,
29
perpMarketConfig.marketIndex,
30
perpMarketConfig.baseDecimals,
31
perpMarketConfig.quoteDecimals,
32
);
33
โ€‹
34
const fills = await perpMarket.loadFills(connection);
35
for (const fill of fills) {
36
console.log(`Filled ${fill.quantity} at ${fill.price}`);
37
}
38
}
39
โ€‹
40
snapshotFills();
Copied!
1
IRpcClient rpcClient = ClientFactory.GetClient(Cluster.MainNet);
2
IStreamingRpcClient streamingRpcClient = ClientFactory.GetStreamingClient(Cluster.MainNet);
3
IMangoClient mangoClient = Solnet.Mango.ClientFactory.GetClient(rpcClient, streamingRpcClient);
4
โ€‹
5
AccountResultWrapper<PerpMarket> perpMarket = await mangoClient.GetPerpMarketAsync("DtEcjPLyD4YtTBB4q8xwFZ9q49W89xZCZtJyrGebi5t8"); // BTC-PERP
6
AccountResultWrapper<EventQueue> eventQueue = await mangoClient.GetEventQueueAsync(perpMarket.ParsedResult.EventQueue, Commitment.Processed);
7
โ€‹
8
List<FillEvent> fills = eventQueue.ParsedResult
9
.Events
10
.Where(f => f.EventType == EventType.Fill)
11
.Cast<FillEvent>()
12
.ToList();
13
โ€‹
14
foreach (FillEvent fill in fills)
15
{
16
Console.WriteLine(quot;Filled {fill.Quantity} @ {fill.Price}");
17
}
Copied!
A 'fill' is when a maker order from the orderbook is matched with an incoming taker order. It can be useful to see these.
This code will connect to the devnet cluster and fetch all recent events. It will then show all the fill events.
1
import mango
2
โ€‹
3
with mango.ContextBuilder.build(cluster_name="devnet") as context:
4
market = mango.market(context, "BTC-PERP")
5
event_queue = mango.PerpEventQueue.load(context, market.event_queue_address, market.lot_size_converter)
6
print(event_queue.fills)
7
โ€‹
8
print("Example complete.")
Copied!

Post Orders

Orders are placed by adding an instruction to a transaction. You can add multiple instructions to a single transaction. There is no additional fee per instruction, your account is only charged per transaction. You can have a max of 64 open orders across all perpetual markets.
TypeScript
C#
Python
1
import {
2
Config,
3
getMarketByBaseSymbolAndKind,
4
GroupConfig,
5
MangoClient,
6
} from '../src';
7
import { Account, Commitment, Connection, PublicKey } from '@solana/web3.js';
8
import configFile from '../src/ids.json';
9
import * as os from 'os';
10
import * as fs from 'fs';
11
โ€‹
12
async function postOrders() {
13
// setup client
14
const config = new Config(configFile);
15
const groupConfig = config.getGroupWithName('mainnet.1') as GroupConfig;
16
const connection = new Connection(
17
config.cluster_urls[groupConfig.cluster],
18
'processed' as Commitment,
19
);
20
const client = new MangoClient(connection, groupConfig.mangoProgramId);
21
โ€‹
22
const payer = new Account(
23
JSON.parse(
24
fs.readFileSync(
25
os.homedir() + '/.config/solana/my-mainnet.json',
26
'utf-8',
27
),
28
),
29
);
30
โ€‹
31
// load group, cache, account, market
32
const mangoAccountPk = new PublicKey('YOUR_MANGOACCOUNT_KEY');
33
const mangoGroup = await client.getMangoGroup(groupConfig.publicKey);
34
const mangoAccount = await client.getMangoAccount(
35
mangoAccountPk,
36
mangoGroup.dexProgramId,
37
);
38
โ€‹
39
const perpMarketConfig = getMarketByBaseSymbolAndKind(
40
groupConfig,
41
'BTC',
42
'perp',
43
);
44
const perpMarket = await mangoGroup.loadPerpMarket(
45
connection,
46
perpMarketConfig.marketIndex,
47
perpMarketConfig.baseDecimals,
48
perpMarketConfig.quoteDecimals,
49
);
50
โ€‹
51
// post an ask for 1btc at 50000
52
await client.placePerpOrder2(
53
mangoGroup,
54
mangoAccount,
55
perpMarket,
56
payer,
57
'sell',
58
50000,
59
1,
60
{
61
orderType: 'postOnly',
62
},
63
);
64
}
65
โ€‹
66
postOrders();
Copied!
1
//Mango Client
2
IRpcClient rpcClient = ClientFactory.GetClient(Cluster.MainNet);
3
IStreamingRpcClient streamingRpcClient = ClientFactory.GetStreamingClient(Cluster.MainNet);
4
IMangoClient mangoClient = Solnet.Mango.ClientFactory.GetClient(rpcClient, streamingRpcClient);
5
โ€‹
6
//Token
7
PublicKey perpMarketPublicKey = new PublicKey("4GkJj2znAr2pE2PBbak66E12zjCs2jkmeafiJwDVM9Au"); // SRM-PERP
8
AccountResultWrapper<MangoGroup> mangoGroup = await mangoClient.GetMangoGroupAsync(Constants.MangoGroup);
9
IPythClient pythClient = Solnet.Pyth.ClientFactory.GetClient(rpcClient, streamingRpcClient);
10
AccountResultWrapper<MappingAccount> mappingAccount = await pythClient.GetMappingAccountAsync(Solnet.Pyth.Constants.MappingAccount);
11
MultipleAccountsResultWrapper<List<ProductAccount>> productAccounts = await pythClient.GetProductAccountsAsync(mappingAccount.ParsedResult);
12
ProductAccount productAccount = productAccounts.ParsedResult.First(x => x.Product.Symbol.Contains("SRM"));
13
PublicKey oracle = mangoGroup.ParsedResult.Oracles.First(x => x.Key == productAccount.PriceAccount.Key);
14
int perpetualMarketIndex = mangoGroup.ParsedResult.Oracles.IndexOf(oracle);
15
int marketIndex = mangoGroup.ParsedResult.GetPerpMarketIndex(perpMarketPublicKey);
16
TokenInfo token = mangoGroup.ParsedResult.Tokens[marketIndex];
17
TokenInfo quoteToken = mangoGroup.ParsedResult.GetQuoteTokenInfo();
18
โ€‹
19
//Market and Pricing
20
AccountResultWrapper<PerpMarket> perpMarket = await mangoClient.GetPerpMarketAsync(perpMarketPublicKey);
21
(long bidPrice, long bidQuantity) = perpMarket.ParsedResult.UiToNativePriceQuantity(1.5, 14156.28539071348, token.Decimals, quoteToken.Decimals);
22
(long askPrice, long askQuantity) = perpMarket.ParsedResult.UiToNativePriceQuantity(2.1, 14156.28539071348, token.Decimals, quoteToken.Decimals);
23
โ€‹
24
//Solana Wallet
25
PublicKey solanaWalletPublicKey = new PublicKey("__your_solana_wallet_public_key__");
26
โ€‹
27
//Mango Account
28
PublicKey mangoAccountPublicKey = new PublicKey("__your_mango_account_public_key__");
29
AccountResultWrapper<MangoAccount> mangoAccount = await mangoClient.GetMangoAccountAsync(mangoAccountPublicKey, Commitment.Processed);
30
โ€‹
31
//Expiry
32
ulong expiryTimestamp = (ulong)new DateTimeOffset(DateTime.UtcNow.AddSeconds(250)).ToUnixTimeSeconds();
33
โ€‹
34
MangoProgram mangoProgram = MangoProgram.CreateMainNet();
35
โ€‹
36
TransactionInstruction bid = mangoProgram.PlacePerpOrder2(
37
mangoGroup: Constants.MangoGroup,
38
mangoAccount: mangoAccountPublicKey,
39
owner: solanaWalletPublicKey,
40
mangoCache: Constants.MangoCache,
41
perpetualMarket: mangoGroup.ParsedResult.PerpetualMarkets[perpetualMarketIndex].Market,
42
bids: perpMarket.ParsedResult.Bids,
43
asks: perpMarket.ParsedResult.Asks,
44
eventQueue: perpMarket.ParsedResult.EventQueue,
45
openOrdersAccounts: mangoAccount.ParsedResult.SpotOpenOrders,
46
side: Side.Buy,
47
orderType: PerpOrderType.PostOnly,
48
price: bidPrice,
49
maxBaseQuantity: bidQuantity,
50
clientOrderId: 1_000_001ul,
51
expiryTimestamp: expiryTimestamp,
52
reduceOnly: false
53
);
54
โ€‹
55
TransactionInstruction ask = mangoProgram.PlacePerpOrder2(
56
mangoGroup: Constants.MangoGroup,
57
mangoAccount: mangoAccountPublicKey,
58
owner: solanaWalletPublicKey,
59
mangoCache: Constants.MangoCache,
60
perpetualMarket: mangoGroup.ParsedResult.PerpetualMarkets[perpetualMarketIndex].Market,
61
bids: perpMarket.ParsedResult.Bids,
62
asks: perpMarket.ParsedResult.Asks,
63
eventQueue: perpMarket.ParsedResult.EventQueue,
64
openOrdersAccounts: mangoAccount.ParsedResult.SpotOpenOrders,
65
side: Side.Sell,
66
orderType: PerpOrderType.PostOnly,
67
price: askPrice,
68
maxBaseQuantity: askQuantity,
69
clientOrderId: 1_000_002ul,
70
expiryTimestamp: expiryTimestamp,
71
reduceOnly: false
72
);
73
โ€‹
74
//Build Transaction
75
RequestResult<ResponseValue<BlockHash>> blockhashRequest = await rpcClient.GetRecentBlockHashAsync();
76
TransactionBuilder txBuilder = new TransactionBuilder().SetFeePayer(solanaWalletPublicKey).SetRecentBlockHash(blockhashRequest.Result.Value.Blockhash);
77
โ€‹
78
txBuilder.AddInstruction(bid);
79
txBuilder.AddInstruction(ask);
80
โ€‹
81
Wallet solanaWallet = new SolanaKeyStoreService().RestoreKeystoreFromFile("__location_of_your_json_wallet_file__");
82
byte[] txBytes = txBuilder.Build(new List<Account>() { solanaWallet.Account });
83
โ€‹
84
//Send Transaction
85
RequestResult<string> transaction = await mangoClient.RpcClient.SendTransactionAsync(txBytes, true, Commitment.Processed);
Copied!
This code will load the 'example' wallet, connect to the devnet cluster, place an order and wait for the order's transaction signature to be confirmed.
The order is an IOC ('Immediate Or Cancel') order to buy 2 SOL-PERP at $1. This order is unlikely to be filled (SOL currently costs substantially more than $1), but that saves having to show order cancellation code here.
Possible order_type values are:
  • mango.OrderType.LIMIT
  • mango.OrderType.IOC
  • mango.OrderType.POST_ONLY
  • mango.OrderType.MARKET (it's nearly always better to use IOC and a price with acceptable slippage)
  • mango.OrderType.POST_ONLY_SLIDE (only available on perp markets)
โ€‹
1
import decimal
2
import mango
3
โ€‹
4
from solana.publickey import PublicKey
5
โ€‹
6
# Use our hard-coded devnet wallet for DeekipCw5jz7UgQbtUbHQckTYGKXWaPQV4xY93DaiM6h.
7
# For real-world use you'd load the bytes from the environment or a file. Later we use
8
# its Mango Account at HhepjyhSzvVP7kivdgJH9bj32tZFncqKUwWidS1ja4xL.
9
wallet = mango.Wallet(bytes([67,218,68,118,140,171,228,222,8,29,48,61,255,114,49,226,239,89,151,110,29,136,149,118,97,189,163,8,23,88,246,35,187,241,107,226,47,155,40,162,3,222,98,203,176,230,34,49,45,8,253,77,136,241,34,4,80,227,234,174,103,11,124,146]))
10
โ€‹
11
with mango.ContextBuilder.build(cluster_name="devnet") as context:
12
group = mango.Group.load(context)
13
account = mango.Account.load(context, PublicKey("HhepjyhSzvVP7kivdgJH9bj32tZFncqKUwWidS1ja4xL"), group)
14
market_operations = mango.operations(context, wallet, account, "SOL-PERP", dry_run=False)
15
โ€‹
16
# Try to buy 2 SOL for $1.
17
order = mango.Order.from_values(side=mango.Side.BUY,
18
price=decimal.Decimal(1),
19
quantity=decimal.Decimal(2),
20
order_type=mango.OrderType.IOC)
21
print("Placing order:", order)
22
placed_order_signatures = market_operations.place_order(order)
23
โ€‹
24
print("Waiting for place order transaction to confirm...\n", placed_order_signatures)
25
mango.WebSocketTransactionMonitor.wait_for_all(
26
context.client.cluster_ws_url, placed_order_signatures, commitment="processed"
27
)
28
โ€‹
29
print("Example complete.")
Copied!

Cancel an Order

You can cancel a specific order by OrderID, Side or ClientID.
TypeScript
C#
Python
1
import {
2
Config,
3
getMarketByBaseSymbolAndKind,
4
GroupConfig,
5
MangoClient,
6
} from '../src';
7
import { Account, Commitment, Connection, PublicKey } from '@solana/web3.js';
8
import configFile from '../src/ids.json';
9
import * as os from 'os';
10
import * as fs from 'fs';
11
import { BN } from 'bn.js';
12
โ€‹
13
async function cancelOrder() {
14
// setup client
15
const config = new Config(configFile);
16
const groupConfig = config.getGroupWithName('mainnet.1') as GroupConfig;
17
const connection = new Connection(
18
config.cluster_urls[groupConfig.cluster],
19
'processed' as Commitment,
20
);
21
const client = new MangoClient(connection, groupConfig.mangoProgramId);
22
โ€‹
23
const payer = new Account(
24
JSON.parse(
25
fs.readFileSync(
26
os.homedir() + '/.config/solana/my-mainnet.json',
27
'utf-8',
28
),
29
),
30
);
31
โ€‹
32
// load group, account, market
33
const mangoAccountPk = new PublicKey('YOUR_MANGOACCOUNT_KEY');
34
const mangoGroup = await client.getMangoGroup(groupConfig.publicKey);
35
const mangoAccount = await client.getMangoAccount(
36
mangoAccountPk,
37
mangoGroup.dexProgramId,
38
);
39
โ€‹
40
const perpMarketConfig = getMarketByBaseSymbolAndKind(
41
groupConfig,
42
'BTC',
43
'perp',
44
);
45
const perpMarket = await mangoGroup.loadPerpMarket(
46
connection,
47
perpMarketConfig.marketIndex,
48
perpMarketConfig.baseDecimals,
49
perpMarketConfig.quoteDecimals,
50
);
51
โ€‹
52
const clientOrderId = 123;
53
// post an ask for 1btc at 50000
54
await client.placePerpOrder2(
55
mangoGroup,
56
mangoAccount,
57
perpMarket,
58
payer,
59
'sell',
60
50000,
61
1,
62
{
63
orderType: 'postOnly',
64
clientOrderId: clientOrderId,
65
},
66
);
67
โ€‹
68
// load open perp orders
69
const orders = await perpMarket.loadOrdersForAccount(
70
connection,
71
mangoAccount,
72
);
73
โ€‹
74
// cancel by client id
75
const order = orders.find((order) => order.clientId == new BN(clientOrderId));
76
await client.cancelPerpOrder(
77
mangoGroup,
78
mangoAccount,
79
payer,
80
perpMarket,
81
order,
82
);
83
}
84
โ€‹
85
cancelOrder();
Copied!
โ€‹
1
//Mango Client
2
IRpcClient rpcClient = Solnet.Rpc.ClientFactory.GetClient(Cluster.MainNet);
3
IStreamingRpcClient streamingRpcClient = ClientFactory.GetStreamingClient(Cluster.MainNet);
4
IMangoClient mangoClient = Solnet.Mango.ClientFactory.GetClient(rpcClient, streamingRpcClient);
5
โ€‹
6
//Solana Wallet
7
PublicKey solanaWalletPublicKey = new PublicKey("__your_solana_wallet_public_key__");
8
โ€‹
9
//Mango Account
10
PublicKey mangoAccountPublicKey = new PublicKey("__your_mango_account_public_key__");
11
AccountResultWrapper<MangoAccount> mangoAccount = await mangoClient.GetMangoAccountAsync(mangoAccountPublicKey, Commitment.Processed);
12
โ€‹
13
//Market
14
PublicKey perpMarketPublicKey = new PublicKey("4GkJj2znAr2pE2PBbak66E12zjCs2jkmeafiJwDVM9Au"); // SRM-PERP
15
AccountResultWrapper<MangoGroup> mangoGroup = await mangoClient.GetMangoGroupAsync(Constants.MangoGroup);
16
AccountResultWrapper<PerpMarket> perpMarket = await mangoClient.GetPerpMarketAsync(perpMarketPublicKey);
17
โ€‹
18
//Market Index
19
IPythClient pythClient = Solnet.Pyth.ClientFactory.GetClient(rpcClient, streamingRpcClient);
20
AccountResultWrapper<MappingAccount> mappingAccount = await pythClient.GetMappingAccountAsync(Solnet.Pyth.Constants.MappingAccount);
21
MultipleAccountsResultWrapper<List<ProductAccount>> productAccounts = await pythClient.GetProductAccountsAsync(mappingAccount.ParsedResult);
22
ProductAccount productAccount = productAccounts.ParsedResult.First(x => x.Product.Symbol.Contains("SRM"));
23
PublicKey oracle = mangoGroup.ParsedResult.Oracles.First(x => x.Key == productAccount.PriceAccount.Key);
24
int perpetualMarketIndex = mangoGroup.ParsedResult.Oracles.IndexOf(oracle);
25
โ€‹
26
MangoProgram mangoProgram = MangoProgram.CreateMainNet();
27
โ€‹
28
TransactionInstruction cancelById = mangoProgram.CancelPerpOrder(
29
mangoGroup: Constants.MangoGroup,
30
mangoAccount: mangoAccountPublicKey,
31
owner: solanaWalletPublicKey,
32
perpetualMarket: mangoGroup.ParsedResult.PerpetualMarkets[perpetualMarketIndex].Market,
33
bids: perpMarket.ParsedResult.Bids,
34
asks: perpMarket.ParsedResult.Asks,
35
orderId: 1_000_001ul,
36
invalidIdOk: false
37
);
38
โ€‹
39
//Build Transaction
40
RequestResult<ResponseValue<BlockHash>> blockhashRequest = await rpcClient.GetRecentBlockHashAsync();
41
TransactionBuilder txBuilder = new TransactionBuilder().SetFeePayer(solanaWalletPublicKey).SetRecentBlockHash(blockhashRequest.Result.Value.Blockhash);
42
โ€‹
43
txBuilder.AddInstruction(cancelById);
44
โ€‹
45
Wallet solanaWallet = new SolanaKeyStoreService().RestoreKeystoreFromFile("__location_of_your_json_wallet_file__");
46
byte[] txBytes = txBuilder.Build(new List<Account>() { solanaWallet.Account });
47
โ€‹
48
//Send Transaction
49
RequestResult<string> transaction = await rpcClient.SendTransactionAsync(txBytes, true, Commitment.Processed);
Copied!
This code will load the 'example' wallet, connect to the devnet cluster, place an order and then cancel it.
This is a bit longer than the Place Order example but only because it performs most of the Place Order code as a setup to create the order so there's an order to cancel.
The key point is that cancel_order() takes an Order as a parameter, and that Order needs either the id or client_id property to be set so the Mango program can find the equivalent order data on-chain. The sample code specified 1001 as the client_id when the order was instantiated so it's fine for use here.
1
import decimal
2
import mango
3
โ€‹
4
from solana.publickey import PublicKey
5
โ€‹
6
# Use our hard-coded devnet wallet for DeekipCw5jz7UgQbtUbHQckTYGKXWaPQV4xY93DaiM6h.
7
# For real-world use you'd load the bytes from the environment or a file. Later we use
8
# its Mango Account at HhepjyhSzvVP7kivdgJH9bj32tZFncqKUwWidS1ja4xL.
9
wallet = mango.Wallet(bytes([67,218,68,118,140,171,228,222,8,29,48,61,255,114,49,226,239,89,151,110,29,136,149,118,97,189,163,8,23,88,246,35,187,241,107,226,47,155,40,162,3,222,98,203,176,230,34,49,45,8,253,77,136,241,34,4,80,227,234,174,103,11,124,146]))
10
โ€‹
11
with mango.ContextBuilder.build(cluster_name="devnet") as context:
12
group = mango.Group.load(context)
13
account = mango.Account.load(context, PublicKey("HhepjyhSzvVP7kivdgJH9bj32tZFncqKUwWidS1ja4xL"), group)
14
market_operations = mango.operations(context, wallet, account, "SOL-PERP", dry_run=False)
15
โ€‹
16
print("Orders (initial):")
17
print(market_operations.load_orderbook())
18
โ€‹
19
order = mango.Order.from_values(side=mango.Side.BUY,
20
price=decimal.Decimal(10),
21
quantity=decimal.Decimal(1),