-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathleverage_position.rs
More file actions
129 lines (105 loc) · 3.97 KB
/
leverage_position.rs
File metadata and controls
129 lines (105 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#![allow(clippy::all)]
use rust_decimal::prelude::*;
use rhyperliquid::{
example_helpers::load_signer,
init_tracing::init_tracing,
response::ResponseInner,
types::exchange::{Grouping, OrderRequest},
HyperliquidClientBuilder, HyperliquidError,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
init_tracing();
let pkey_signer = load_signer();
let mut builder = HyperliquidClientBuilder::new();
let hyperliquid = builder.testnet().with_wallet(pkey_signer.clone()).build()?;
let info_api = hyperliquid.info();
let exchange_api = hyperliquid.exchange();
// Get current price from meta and asset contexts
let (perp_meta, asset_ctxs) = info_api.perpetuals_asset_contexts().await?;
let btc_asset_and_idx = perp_meta
.universe
.iter()
.enumerate()
.find(|asset| asset.1.name == "BTC");
let (asset_idx, asset_info) = btc_asset_and_idx.ok_or(HyperliquidError::Internal(
"Missing asset in universe".to_string(),
))?;
let btc_ctx = &asset_ctxs
.get(asset_idx)
.ok_or(HyperliquidError::Internal("Asset not found".to_string()))?;
let mark_price = btc_ctx.mark_px;
tracing::info!("BTC mark price: ${}", mark_price);
let multiplier = Decimal::from_str("1.01")?;
let order_price_decimal = mark_price.saturating_mul(multiplier);
let min_notional = Decimal::from(10);
let min_size =
min_notional
.checked_div(order_price_decimal)
.ok_or(HyperliquidError::InvalidPrice(
"Price cannot be 0".to_string(),
))?;
// Round up to sz_decimals precision
let sz_decimals = u32::try_from(asset_info.sz_decimals)?;
let size = min_size.round_dp_with_strategy(sz_decimals, RoundingStrategy::AwayFromZero);
tracing::info!("Calculated size: {}", size);
tracing::info!(
"Notional value: {}",
size.saturating_mul(order_price_decimal)
);
tracing::info!("Setting leverage to 5x isolated");
let leverage_response = exchange_api
.update_leverage(u32::try_from(asset_idx)?, false, 5, None, None)
.await?;
match leverage_response.response {
ResponseInner::Error(e) => {
tracing::error!("Failed to update leverage: {:?}", e);
return Ok(());
}
ResponseInner::Ok(_) => {
tracing::info!("Successfully set leverage to 5x isolated");
}
}
// Place market order using the builder
tracing::info!("Placing market buy order");
let order_req = OrderRequest::new_market_order(
u32::try_from(asset_idx)?,
asset_info,
true,
order_price_decimal,
size,
);
let order_response = exchange_api
.place_order(order_req, Grouping::Na, None, None, None)
.await?;
match order_response.response {
ResponseInner::Error(e) => {
tracing::error!("Failed to place order: {:?}", e);
return Ok(());
}
ResponseInner::Ok(order_data) => {
tracing::info!("Order placed: {:?}", order_data);
}
}
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
tracing::info!("Adding 5 USDC to isolated margin");
let add_margin_response = exchange_api
.update_isolated_margin(u32::try_from(asset_idx)?, true, 5_000_000, None, None)
.await?;
match add_margin_response.response {
ResponseInner::Error(e) => {
tracing::error!("Failed to add margin: {:?}", e);
}
ResponseInner::Ok(_) => {
tracing::info!("Successfully added 5 USDC margin");
}
}
let wallet_address = pkey_signer.address();
let user_state = info_api
.perpetuals_account_summary(&wallet_address.to_string(), None)
.await?;
tracing::info!("Final account state:");
tracing::info!("Margin summary: {:?}", user_state.margin_summary);
tracing::info!("Asset positions: {:?}", user_state.asset_positions);
Ok(())
}