-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy path.cursorrules
More file actions
357 lines (310 loc) · 13.9 KB
/
Copy path.cursorrules
File metadata and controls
357 lines (310 loc) · 13.9 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# Background
Client libraries for use in a High Frequency trading systems.
They aim to be as high performant and low latency as possible in rust.
Code that is complex but fast (whilst still correct) is preferred over cleaner yet slower code.
# Common supporting code
For code in crates that support each venue, such as websockets, no venue specific code or knowledge of the venues is allowed. The code must be clean.
# URL Encoding Rules
- When encoding URL query strings (e.g., for REST API requests), always use the `serde_urlencoded` crate to serialize parameters. Do not manually build or concatenate query strings, and do not use hand-rolled solutions for URL encoding.
# File Structure Rules
1. All endpoint files MUST be directly under the venue directory (e.g. venues/src/binance/coinm/)
2. NO subdirectories for endpoints are allowed
3. File naming convention:
- Private REST endpoints: private_*.rs
- Public REST endpoints: public_*.rs
- Private WebSocket endpoints: ws_private_*.rs
- Public WebSocket endpoints: ws_public_*.rs
4. Each endpoint should be in its own file
5. All wrappers around the endpoints should be pure. No fixes and helper functions.
6. Common code (like websockets, rate limiting) can be in subdirectories
# Struct Implementation Rules
1. The struct definition MUST be in a single file (e.g. private_rest.rs for the client struct)
2. Additional implementations (impl blocks) for the struct can be spread across multiple files
3. Each endpoint file should contain:
- The endpoints types (Request/Response structs)
- An impl block for the client struct with the endpoints implementation
4. The client structs fields should remain private, with implementations accessing them through self
5. Any fields for API keys, secrets, or passphrases MUST use `SecretString` as their type and be documented accordingly
# Struct Documentation Rules
1. All structs MUST have a doc comment explaining their purpose and usage
2. All struct fields MUST have doc comments that include:
- A clear description of the field's purpose
- Valid values or ranges where applicable
- Any constraints or requirements
- Relationships with other fields
- Units or formats where relevant
3. Field documentation MUST be consistent with the venue's API documentation
4. Documentation MUST be clear and concise, avoiding unnecessary verbosity
5. Documentation MUST use proper Rust doc comment format (///)
6. Documentation MUST be kept up to date with any changes to the struct or its fields
7. Request and Response structs MUST have a blank line between each field for improved readability
8. Field names in serde attributes MUST exactly match the venue's API documentation:
- Carefully verify the exact casing (camelCase, snake_case, SCREAMING_SNAKE_CASE, etc.)
- Double-check field names against the official API documentation
- Use serde attributes to map between Rust's snake_case and the venue's naming convention
- Example:
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct SomeRequest {
/// The trading pair (e.g., "BTCUSD").
#[serde(rename = "tradingPair")] // Exact match to API docs
pub trading_pair: String,
/// The order type (e.g., "LIMIT").
#[serde(rename = "orderType")] // Exact match to API docs
pub order_type: OrderType,
/// The price of the order.
#[serde(rename = "price")] // Exact match to API docs
pub price: String,
}
```
# Struct Field Naming Rules
1. All struct fields MUST use Rust naming conventions (snake_case)
2. When the API uses different naming conventions (e.g., camelCase), use serde attributes to map the fields:
```rust
#[serde(rename = "apiFieldName")]
pub rust_field_name: Type
```
3. Avoid using raw identifiers (r#) for reserved keywords - use descriptive names instead
4. Keep field names consistent across related structs
# Endpoint Function Documentation Rules
1. All endpoint function wrappers MUST include a link to the official API documentation
2. The documentation link MUST be included in the function's doc comment
3. The link should be placed after the function description and before other details
4. Use the format: `/// See: <URL>` or `/// Documentation: <URL>`
5. Example:
```rust
/// Fetches the user's account information, including assets and positions.
/// See: https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data
/// Corresponds to endpoint GET /dapi/v1/account.
/// Requires API key authentication.
/// Weight: 5
pub async fn get_account(&self) -> BinanceCoinMResult<AccountResponse> {
// implementation
}
```
6. The documentation link MUST point to the official venue API documentation
7. Links MUST be kept up to date with any changes to the venue's documentation structure
# Enum Usage Rules
1. All response structs MUST use enums for fields that represent fixed sets of values:
- Fields that have a predefined set of possible values
- Fields that represent states or types
- Fields that represent categories or classifications
- Fields that represent modes or configurations
- Fields that represent directions or sides
- Fields that represent statuses or conditions
2. Enums MUST be defined in the venues enums.rs file
3. Enums MUST implement:
- Debug
- Clone
- Copy
- PartialEq
- Eq
- Serialize
- Deserialize
4. Enum variants MUST use the venues API naming convention (typically SCREAMING_SNAKE_CASE) for compatibility:
```rust
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] // or whatever the venue uses
pub enum SomeEnum {
Variant1,
Variant2,
}
```
5. DO NOT use String types for fields that should be enums
6. DO NOT use raw strings for fields that represent fixed sets of values
# File Structure Example
venues/src/binance/coinm/
├── private_order.rs # ✓ Correct
├── private_account.rs # ✓ Correct
├── public_ticker.rs # ✓ Correct
├── ws_private_trades.rs # ✓ Correct
├── ws_public_depth.rs # ✓ Correct
├── common/ # ✓ Allowed for common code
│ ├── websocket.rs
│ └── rate_limit.rs
└── private_rest/ # ✗ Wrong - no subdirectories for endpoints
├── order.rs
└── account.rs
# DO NOT
- Put endpoint files in subdirectories
- Use different naming conventions
- Combine multiple endpoints in one file
- Use String types for fields that should be enums
- Create enums in endpoint files
- Use raw strings for fields with fixed sets of values
# Error Handling Rules
1. Error Enum Structure:
- Each venue MUST define an error enum with:
- Error code as a field
- Descriptive message field
- Any other fields that are relevant to the venue
- Proper error variants for all possible API errors
```rust
#[derive(Error, Debug)]
pub enum VenueError {
#[error("Error {code}: {message}")]
SpecificError {
code: i32,
message: String,
},
// ... other variants
}
```
2. Error Response Structure:
- Each venue MUST define an error response struct:
- Additional fields can be added to the error response struct to include more information per venue
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct VenueErrorResponse {
pub code: i32,
pub msg: String,
}
```
3. Error Mapping Implementation:
- Each venue MUST implement From<VenueErrorResponse> for VenueError
- Map all known error codes to specific error variants
- Include an Unknown variant for unmapped codes
```rust
impl From<VenueErrorResponse> for VenueError {
fn from(err: VenueErrorResponse) -> Self {
match err.code {
-1000 => VenueError::SpecificError {
code: err.code,
message: err.msg,
},
// ... other mappings
_ => VenueError::Unknown {
code: err.code,
message: err.msg,
},
}
}
}
```
4. HTTP Status Code Mapping:
- Each HTTP status code MUST map to a specific error code
- The mapping MUST be documented in the error enum
- Example:
```rust
match status {
StatusCode::UNAUTHORIZED => VenueError::AuthenticationError {
code: -2015,
message: "Invalid API key".to_string(),
},
// ... other mappings
}
```
5. Error Documentation:
- Each error variant MUST have a doc comment explaining:
- The error code
- When it occurs
- How to handle it
- Example:
```rust
/// Error -2015: Invalid API key
/// Occurs when the API key is invalid or has insufficient permissions
/// Handle by checking API key validity and permissions
#[error("Authentication error: {message} (code: {code})")]
AuthenticationError {
code: i32,
message: String,
}
```
6. Error Type Alias:
- Each venue MUST define a Result type alias:
```rust
pub type VenueResult<T> = Result<T, VenueError>;
```
7. Error Handling in Functions:
- All functions MUST return the venues Result type
- Error handling MUST use the ? operator to propagate errors
- Error messages MUST be preserved from the API when available
8. Common Error Categories:
- Authentication errors (e.g., invalid API key)
- Rate limiting errors
- Validation errors (e.g., invalid parameters)
- Server errors
- Network errors
- Unknown errors
9. Error Code Ranges:
- Each venue SHOULD document their error code ranges
- Example:
```rust
/// Error code ranges:
/// -1000 to -1999: General errors
/// -2000 to -2999: Authentication errors
/// -3000 to -3999: Rate limiting errors
/// -4000 to -4999: Validation errors
/// -5000 to -5999: Server errors
```
10. Error Handling Best Practices:
- NEVER use regex for parsing error messages
- Keep error handling simple and direct
- Preserve original error codes and messages
- Use direct string matching or simple string operations
- Avoid complex parsing of error messages
- When in doubt, pass through the original error message
# Error Modelling Rules for All Exchanges
1. All exchange errors MUST be modelled as Rust structs.
- The error struct must include a dynamic error message field (e.g., `msg: String`).
- The struct should represent all relevant fields returned by the exchange for error responses.
- Example:
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct ExchangeErrorResponse {
pub code: i32,
pub msg: String, // dynamic error message
// ... other fields as needed
}
```
2. All API function return types MUST be an enum covering:
- Rust native errors (e.g., std::io::Error, serde_json::Error, etc.)
- HTTP errors (e.g., reqwest::Error)
- API errors (modelled as above, e.g., ExchangeAPIError)
- Example:
```rust
pub enum ExchangeError {
ApiError(ExchangeAPIError),
HttpError(reqwest::Error),
NativeError(Box<dyn std::error::Error + Send + Sync>),
}
pub type ExchangeResult<T> = Result<T, ExchangeError>;
```
3. The error enum should implement `std::error::Error` and `Display` for proper error propagation and formatting.
4. All error messages returned from the exchange MUST be preserved and passed through to the user.
5. This pattern MUST be applied consistently across all exchanges in the codebase.
# Common Mistakes to Avoid
1. Using regex for error message parsing
2. Over-complicating error handling logic
3. Trying to extract structured data from error messages
4. Adding unnecessary dependencies for error handling
5. Creating complex error message parsing logic
6. Not preserving original error codes and messages
7. Not documenting error variants
8. Not implementing proper error mapping
9. Not handling all possible error cases
10. Not using the venues Result type alias
11. Creating subdirectories for endpoints (e.g. private_rest/, public_rest/)
12. Using incorrect prefixes (e.g. rest_private_*.rs instead of private_*.rs)
13. Combining multiple endpoints in one file
14. Making struct fields public to access them from other files
15. Moving endpoint implementations to the struct definition file
16. Using String types for fields that should be enums
17. Creating enums in endpoint files instead of enums.rs
18. Using raw strings for fields with fixed sets of values
# Rate Limiting Implementations
1. Use existing rate limiter crates for implementing rate limiting functionality
2. Rate limiting logic MUST be separated from endpoint implementations
3. Each venue SHOULD define its own rate limiting configuration based on API documentation
# Websockets
1. All websocket implementations MUST implement the common websocket trait defined in the websockets crate at the root level
2. Websocket implementations MUST be venue-agnostic in the common websockets crate
3. Venue-specific websocket logic MUST be implemented in the venue's specific module
4. Websocket connections MUST handle reconnection and error recovery automatically
5. All websocket messages MUST be properly typed with request/response structs
# API Credential Handling Rules
1. All API keys, secrets, and passphrases MUST be passed as parameters of type `impl Into<SecretString>` in constructors and functions, instead of `String` or any other data types.
2. All struct fields that store API keys, secrets, or passphrases MUST use `SecretString` as their type.
3. Do NOT use `String`, `&str`, or any other type for storing or passing API credentials.
4. This applies to all venues and all client structs, request structs, and any other relevant types.
5. Documentation for these fields MUST clearly state that the value is stored securely and is expected to be provided as a `SecretString`.