future-private: add placePositionTpSlOrder request
This commit is contained in:
parent
bf185918e1
commit
2fde2137e4
30
README.md
30
README.md
|
|
@ -217,6 +217,32 @@ if ($response->getStatusCode() === 200) {
|
|||
}
|
||||
```
|
||||
|
||||
### Place Position TP/SL Order
|
||||
|
||||
```php
|
||||
use Msr\LaravelBitunixApi\Requests\PlacePositionTpSlOrderRequestContract;
|
||||
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
// Place position TP/SL order with both take profit and stop loss
|
||||
$response = $api->placePositionTpSlOrder(
|
||||
'BTCUSDT', // symbol
|
||||
'111', // positionId
|
||||
'50000', // tpPrice
|
||||
'LAST_PRICE', // tpStopType
|
||||
'45000', // slPrice
|
||||
'LAST_PRICE' // slStopType
|
||||
);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$data = json_decode($response->getBody()->getContents(), true);
|
||||
if ($data['code'] === 0) {
|
||||
echo "Position TP/SL order placed successfully!";
|
||||
echo "Order ID: " . $data['data']['orderId'];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Get Future Kline Data
|
||||
|
||||
```php
|
||||
|
|
@ -243,6 +269,7 @@ if ($response->getStatusCode() === 200) {
|
|||
|
||||
- `placeOrder(...)` - Place a new order with full support for all order types, take profit, stop loss, and position management
|
||||
- `placeTpSlOrder(...)` - Place TP/SL order for existing positions
|
||||
- `placePositionTpSlOrder(...)` - Place position TP/SL order (closes position at market price when triggered)
|
||||
- `flashClosePosition(string $positionId)` - Flash close position by position ID
|
||||
|
||||
### Position Management
|
||||
|
|
@ -269,6 +296,7 @@ if ($response->getStatusCode() === 200) {
|
|||
- **Get Single Account**: 10 req/sec/uid
|
||||
- **Place Order**: 10 req/sec/uid
|
||||
- **Place TP/SL Order**: 10 req/sec/uid
|
||||
- **Place Position TP/SL Order**: 10 req/sec/uid
|
||||
- **Flash Close Position**: 5 req/sec/uid
|
||||
- **Get Pending Positions**: 10 req/sec/uid
|
||||
|
||||
|
|
@ -311,6 +339,7 @@ vendor/bin/pest tests/ChangeMarginModeTest.php
|
|||
vendor/bin/pest tests/GetSingleAccountTest.php
|
||||
vendor/bin/pest tests/PlaceOrderTest.php
|
||||
vendor/bin/pest tests/PlaceTpSlOrderTest.php
|
||||
vendor/bin/pest tests/PlacePositionTpSlOrderTest.php
|
||||
vendor/bin/pest tests/FlashClosePositionTest.php
|
||||
vendor/bin/pest tests/GetPendingPositionsTest.php
|
||||
vendor/bin/pest tests/HeaderTest.php
|
||||
|
|
@ -325,6 +354,7 @@ See the `examples/` directory for complete usage examples:
|
|||
- `GetSingleAccountExample.php`
|
||||
- `PlaceOrderExample.php`
|
||||
- `PlaceTpSlOrderExample.php`
|
||||
- `PlacePositionTpSlOrderExample.php`
|
||||
- `FlashClosePositionExample.php`
|
||||
- `GetPendingPositionsExample.php`
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Example usage of Place Position TP/SL Order functionality
|
||||
*
|
||||
* This example demonstrates how to use the LaravelBitunixApi package
|
||||
* to place position TP/SL orders on Bitunix exchange.
|
||||
*
|
||||
* Note: When triggered, it will close the position at market price based on the position quantity at that time.
|
||||
* Each position can only have one Position TP/SL Order.
|
||||
*/
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
use Msr\LaravelBitunixApi\Requests\PlacePositionTpSlOrderRequestContract;
|
||||
|
||||
// Example configuration (in real usage, these would be in your .env file)
|
||||
config([
|
||||
'bitunix-api.future_base_uri' => 'https://fapi.bitunix.com/',
|
||||
'bitunix-api.api_key' => 'your-api-key-here',
|
||||
'bitunix-api.api_secret' => 'your-api-secret-here',
|
||||
'bitunix-api.language' => 'en-US',
|
||||
]);
|
||||
|
||||
try {
|
||||
// Get the API instance
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
echo "🎯 Place Position TP/SL Order Examples\n\n";
|
||||
|
||||
// Example 1: Place position TP/SL order with both take profit and stop loss
|
||||
echo "1. Placing position TP/SL order with both TP and SL...\n";
|
||||
$response = $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
'50000', // tpPrice
|
||||
'LAST_PRICE', // tpStopType
|
||||
'45000', // slPrice
|
||||
'LAST_PRICE' // slStopType
|
||||
);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$data = json_decode($response->getBody()->getContents(), true);
|
||||
if ($data['code'] === 0) {
|
||||
echo "✅ Position TP/SL order placed successfully!\n";
|
||||
echo 'Order ID: '.$data['data']['orderId']."\n";
|
||||
} else {
|
||||
echo '❌ API Error: '.$data['msg']."\n";
|
||||
}
|
||||
} else {
|
||||
echo '❌ HTTP Error: '.$response->getStatusCode()."\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 2: Place position TP/SL order with take profit only
|
||||
echo "2. Placing position TP/SL order with take profit only...\n";
|
||||
$response = $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
'50000', // tpPrice
|
||||
'MARK_PRICE' // tpStopType
|
||||
);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$data = json_decode($response->getBody()->getContents(), true);
|
||||
if ($data['code'] === 0) {
|
||||
echo "✅ Position TP order placed successfully!\n";
|
||||
echo 'Order ID: '.$data['data']['orderId']."\n";
|
||||
} else {
|
||||
echo '❌ API Error: '.$data['msg']."\n";
|
||||
}
|
||||
} else {
|
||||
echo '❌ HTTP Error: '.$response->getStatusCode()."\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 3: Place position TP/SL order with stop loss only
|
||||
echo "3. Placing position TP/SL order with stop loss only...\n";
|
||||
$response = $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
null, // tpPrice
|
||||
null, // tpStopType
|
||||
'45000', // slPrice
|
||||
'MARK_PRICE' // slStopType
|
||||
);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$data = json_decode($response->getBody()->getContents(), true);
|
||||
if ($data['code'] === 0) {
|
||||
echo "✅ Position SL order placed successfully!\n";
|
||||
echo 'Order ID: '.$data['data']['orderId']."\n";
|
||||
} else {
|
||||
echo '❌ API Error: '.$data['msg']."\n";
|
||||
}
|
||||
} else {
|
||||
echo '❌ HTTP Error: '.$response->getStatusCode()."\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 4: Place position TP/SL order with different symbols
|
||||
echo "4. Placing position TP/SL orders for different symbols...\n";
|
||||
$symbols = ['BTCUSDT', 'ETHUSDT', 'ADAUSDT'];
|
||||
|
||||
foreach ($symbols as $symbol) {
|
||||
echo "Placing position TP/SL order for {$symbol}...\n";
|
||||
|
||||
$response = $api->placePositionTpSlOrder(
|
||||
$symbol,
|
||||
'111',
|
||||
'50000',
|
||||
'LAST_PRICE',
|
||||
'45000',
|
||||
'LAST_PRICE'
|
||||
);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$data = json_decode($response->getBody()->getContents(), true);
|
||||
if ($data['code'] === 0) {
|
||||
echo "✅ {$symbol} position TP/SL order placed successfully!\n";
|
||||
echo 'Order ID: '.$data['data']['orderId']."\n";
|
||||
} else {
|
||||
echo "❌ Failed to place {$symbol} position TP/SL order: ".$data['msg']."\n";
|
||||
}
|
||||
} else {
|
||||
echo "❌ HTTP Error for {$symbol}: ".$response->getStatusCode()."\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 5: Place position TP/SL order with different position IDs
|
||||
echo "5. Placing position TP/SL orders for different position IDs...\n";
|
||||
$positionIds = ['111', '222', '333'];
|
||||
|
||||
foreach ($positionIds as $positionId) {
|
||||
echo "Placing position TP/SL order for position ID {$positionId}...\n";
|
||||
|
||||
$response = $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
$positionId,
|
||||
'50000',
|
||||
'LAST_PRICE',
|
||||
'45000',
|
||||
'LAST_PRICE'
|
||||
);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$data = json_decode($response->getBody()->getContents(), true);
|
||||
if ($data['code'] === 0) {
|
||||
echo "✅ Position {$positionId} TP/SL order placed successfully!\n";
|
||||
echo 'Order ID: '.$data['data']['orderId']."\n";
|
||||
} else {
|
||||
echo "❌ Failed to place position {$positionId} TP/SL order: ".$data['msg']."\n";
|
||||
}
|
||||
} else {
|
||||
echo "❌ HTTP Error for position {$positionId}: ".$response->getStatusCode()."\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 6: Place position TP/SL order with different stop types
|
||||
echo "6. Placing position TP/SL orders with different stop types...\n";
|
||||
$stopTypeCombinations = [
|
||||
['LAST_PRICE', 'LAST_PRICE'],
|
||||
['MARK_PRICE', 'MARK_PRICE'],
|
||||
['LAST_PRICE', 'MARK_PRICE'],
|
||||
['MARK_PRICE', 'LAST_PRICE'],
|
||||
];
|
||||
|
||||
foreach ($stopTypeCombinations as $index => $combination) {
|
||||
echo "Placing position TP/SL order with stop types: {$combination[0]}, {$combination[1]}...\n";
|
||||
|
||||
$response = $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
'50000',
|
||||
$combination[0],
|
||||
'45000',
|
||||
$combination[1]
|
||||
);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$data = json_decode($response->getBody()->getContents(), true);
|
||||
if ($data['code'] === 0) {
|
||||
echo "✅ Position TP/SL order with {$combination[0]}/{$combination[1]} placed successfully!\n";
|
||||
echo 'Order ID: '.$data['data']['orderId']."\n";
|
||||
} else {
|
||||
echo "❌ Failed to place position TP/SL order: ".$data['msg']."\n";
|
||||
}
|
||||
} else {
|
||||
echo "❌ HTTP Error: ".$response->getStatusCode()."\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// Example 7: Error handling
|
||||
echo "7. Error handling example...\n";
|
||||
$response = $api->placePositionTpSlOrder('INVALID', '111');
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$data = json_decode($response->getBody()->getContents(), true);
|
||||
if ($data['code'] === 0) {
|
||||
echo "✅ Position TP/SL order placed successfully!\n";
|
||||
} else {
|
||||
echo '❌ API Error: '.$data['msg']."\n";
|
||||
echo "This is expected for invalid symbol\n";
|
||||
}
|
||||
} else {
|
||||
echo '❌ HTTP Error: '.$response->getStatusCode()."\n";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo '❌ Exception: '.$e->getMessage()."\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Place Position TP/SL Order Features:
|
||||
*
|
||||
* - Place position TP/SL orders for existing positions
|
||||
* - Rate limit: 10 req/sec/UID
|
||||
* - Supports both take profit and stop loss
|
||||
* - When triggered, closes position at market price
|
||||
* - Each position can only have one Position TP/SL Order
|
||||
*
|
||||
* Required Parameters:
|
||||
* - symbol: Trading pair
|
||||
* - positionId: Position ID associated with TP/SL
|
||||
*
|
||||
* Optional Parameters:
|
||||
* - tpPrice: Take-profit trigger price
|
||||
* - tpStopType: Take-profit trigger type (LAST_PRICE/MARK_PRICE)
|
||||
* - slPrice: Stop-loss trigger price
|
||||
* - slStopType: Stop-loss trigger type (LAST_PRICE/MARK_PRICE)
|
||||
*
|
||||
* Note: At least one of tpPrice or slPrice is required.
|
||||
*
|
||||
* Key Differences from regular TP/SL Order:
|
||||
* - Simpler parameters (no order types, prices, quantities)
|
||||
* - Automatically closes position at market price when triggered
|
||||
* - One order per position limit
|
||||
* - Uses position/place_order endpoint
|
||||
*
|
||||
* Environment Variables Required:
|
||||
*
|
||||
* BITUNIX_API_KEY=your-api-key
|
||||
* BITUNIX_API_SECRET=your-api-secret
|
||||
* BITUNIX_LANGUAGE=en-US
|
||||
*/
|
||||
|
|
@ -11,10 +11,11 @@ use Msr\LaravelBitunixApi\Requests\GetPendingPositionsRequestContract;
|
|||
use Msr\LaravelBitunixApi\Requests\GetSingleAccountRequestContract;
|
||||
use Msr\LaravelBitunixApi\Requests\Header;
|
||||
use Msr\LaravelBitunixApi\Requests\PlaceOrderRequestContract;
|
||||
use Msr\LaravelBitunixApi\Requests\PlacePositionTpSlOrderRequestContract;
|
||||
use Msr\LaravelBitunixApi\Requests\PlaceTpSlOrderRequestContract;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class LaravelBitunixApi implements ChangeLeverageRequestContract, ChangeMarginModeRequestContract, FlashClosePositionRequestContract, FutureKLineRequestContract, GetPendingPositionsRequestContract, GetSingleAccountRequestContract, PlaceOrderRequestContract, PlaceTpSlOrderRequestContract
|
||||
class LaravelBitunixApi implements ChangeLeverageRequestContract, ChangeMarginModeRequestContract, FlashClosePositionRequestContract, FutureKLineRequestContract, GetPendingPositionsRequestContract, GetSingleAccountRequestContract, PlaceOrderRequestContract, PlaceTpSlOrderRequestContract, PlacePositionTpSlOrderRequestContract
|
||||
{
|
||||
private Client $publicFutureClient;
|
||||
|
||||
|
|
@ -260,4 +261,38 @@ class LaravelBitunixApi implements ChangeLeverageRequestContract, ChangeMarginMo
|
|||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function placePositionTpSlOrder(
|
||||
string $symbol,
|
||||
string $positionId,
|
||||
?string $tpPrice = null,
|
||||
?string $tpStopType = null,
|
||||
?string $slPrice = null,
|
||||
?string $slStopType = null
|
||||
): ResponseInterface {
|
||||
$body = [
|
||||
'symbol' => $symbol,
|
||||
'positionId' => $positionId,
|
||||
];
|
||||
|
||||
// Add optional parameters if provided
|
||||
if ($tpPrice !== null) {
|
||||
$body['tpPrice'] = $tpPrice;
|
||||
}
|
||||
if ($tpStopType !== null) {
|
||||
$body['tpStopType'] = $tpStopType;
|
||||
}
|
||||
if ($slPrice !== null) {
|
||||
$body['slPrice'] = $slPrice;
|
||||
}
|
||||
if ($slStopType !== null) {
|
||||
$body['slStopType'] = $slStopType;
|
||||
}
|
||||
|
||||
$response = $this->getPrivateFutureClient([], $body)->post('tpsl/position/place_order', [
|
||||
'json' => $body,
|
||||
]);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ use Msr\LaravelBitunixApi\Requests\FutureKLineRequestContract;
|
|||
use Msr\LaravelBitunixApi\Requests\GetPendingPositionsRequestContract;
|
||||
use Msr\LaravelBitunixApi\Requests\GetSingleAccountRequestContract;
|
||||
use Msr\LaravelBitunixApi\Requests\PlaceOrderRequestContract;
|
||||
use Msr\LaravelBitunixApi\Requests\PlacePositionTpSlOrderRequestContract;
|
||||
use Msr\LaravelBitunixApi\Requests\PlaceTpSlOrderRequestContract;
|
||||
use Spatie\LaravelPackageTools\Package;
|
||||
use Spatie\LaravelPackageTools\PackageServiceProvider;
|
||||
|
||||
|
|
@ -41,5 +43,7 @@ class LaravelBitunixApiServiceProvider extends PackageServiceProvider
|
|||
$this->app->bind(FlashClosePositionRequestContract::class, LaravelBitunixApi::class);
|
||||
$this->app->bind(GetPendingPositionsRequestContract::class, LaravelBitunixApi::class);
|
||||
$this->app->bind(GetSingleAccountRequestContract::class, LaravelBitunixApi::class);
|
||||
$this->app->bind(PlaceTpSlOrderRequestContract::class, LaravelBitunixApi::class);
|
||||
$this->app->bind(PlacePositionTpSlOrderRequestContract::class, LaravelBitunixApi::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Msr\LaravelBitunixApi\Requests;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface PlacePositionTpSlOrderRequestContract
|
||||
{
|
||||
/**
|
||||
* Place Position TP/SL Order
|
||||
* When triggered, it will close the position at market price based on the position quantity at that time.
|
||||
* Each position can only have one Position TP/SL Order
|
||||
*
|
||||
* @param string $symbol Trading pair
|
||||
* @param string $positionId Position ID associated with take-profit and stop-loss
|
||||
* @param string|null $tpPrice Take-profit trigger price
|
||||
* @param string|null $tpStopType Take-profit trigger type (LAST_PRICE/MARK_PRICE)
|
||||
* @param string|null $slPrice Stop-loss trigger price
|
||||
* @param string|null $slStopType Stop-loss trigger type (LAST_PRICE/MARK_PRICE)
|
||||
*/
|
||||
public function placePositionTpSlOrder(
|
||||
string $symbol,
|
||||
string $positionId,
|
||||
?string $tpPrice = null,
|
||||
?string $tpStopType = null,
|
||||
?string $slPrice = null,
|
||||
?string $slStopType = null
|
||||
): ResponseInterface;
|
||||
}
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
<?php
|
||||
|
||||
use Msr\LaravelBitunixApi\Requests\PlacePositionTpSlOrderRequestContract;
|
||||
|
||||
beforeEach(function () {
|
||||
config([
|
||||
'bitunix-api.future_base_uri' => 'https://fapi.bitunix.com/',
|
||||
'bitunix-api.api_key' => 'test-api-key',
|
||||
'bitunix-api.api_secret' => 'test-secret-key',
|
||||
'bitunix-api.language' => 'en-US',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can place position TP/SL order with required parameters only', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
expect(fn() => $api->placePositionTpSlOrder('BTCUSDT', '111'))
|
||||
->not->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
it('can place position TP/SL order with take profit only', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
expect(fn() => $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
'50000', // tpPrice
|
||||
'LAST_PRICE' // tpStopType
|
||||
))->not->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
it('can place position TP/SL order with stop loss only', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
expect(fn() => $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
null, // tpPrice
|
||||
null, // tpStopType
|
||||
'45000', // slPrice
|
||||
'LAST_PRICE' // slStopType
|
||||
))->not->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
it('can place position TP/SL order with both take profit and stop loss', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
expect(fn() => $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
'50000', // tpPrice
|
||||
'LAST_PRICE', // tpStopType
|
||||
'45000', // slPrice
|
||||
'LAST_PRICE' // slStopType
|
||||
))->not->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
it('validates place position TP/SL order method exists', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
expect(method_exists($api, 'placePositionTpSlOrder'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('can handle different symbol formats', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
$symbols = ['BTCUSDT', 'ETHUSDT', 'ADAUSDT'];
|
||||
|
||||
foreach ($symbols as $symbol) {
|
||||
expect(fn() => $api->placePositionTpSlOrder($symbol, '111'))
|
||||
->not->toThrow(Exception::class);
|
||||
}
|
||||
});
|
||||
|
||||
it('can handle different position ID formats', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
$positionIds = ['111', 'position-123', '19848247723672'];
|
||||
|
||||
foreach ($positionIds as $positionId) {
|
||||
expect(fn() => $api->placePositionTpSlOrder('BTCUSDT', $positionId))
|
||||
->not->toThrow(Exception::class);
|
||||
}
|
||||
});
|
||||
|
||||
it('can handle different stop types', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
$stopTypes = ['LAST_PRICE', 'MARK_PRICE'];
|
||||
|
||||
foreach ($stopTypes as $stopType) {
|
||||
expect(fn() => $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
'50000',
|
||||
$stopType,
|
||||
'45000',
|
||||
$stopType
|
||||
))->not->toThrow(Exception::class);
|
||||
}
|
||||
});
|
||||
|
||||
it('can handle different price formats', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
$prices = ['50000', '50000.1', '50000.01', '50000.001'];
|
||||
|
||||
foreach ($prices as $price) {
|
||||
expect(fn() => $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
$price,
|
||||
'LAST_PRICE',
|
||||
'45000',
|
||||
'LAST_PRICE'
|
||||
))->not->toThrow(Exception::class);
|
||||
}
|
||||
});
|
||||
|
||||
it('can handle multiple place position TP/SL order calls', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
$calls = [
|
||||
['BTCUSDT', '111'],
|
||||
['ETHUSDT', '222', '3000', 'LAST_PRICE'],
|
||||
['ADAUSDT', '333', null, null, '0.5', 'LAST_PRICE'],
|
||||
['BTCUSDT', '444', '50000', 'LAST_PRICE', '45000', 'LAST_PRICE'],
|
||||
];
|
||||
|
||||
foreach ($calls as $params) {
|
||||
expect(fn() => $api->placePositionTpSlOrder(...$params))
|
||||
->not->toThrow(Exception::class);
|
||||
}
|
||||
});
|
||||
|
||||
it('validates place position TP/SL order response structure', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
// This test verifies the method can be called without throwing exceptions
|
||||
// The actual response structure will be validated by the API
|
||||
expect(fn() => $api->placePositionTpSlOrder('BTCUSDT', '111'))
|
||||
->not->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
it('can handle edge cases for position TP/SL order', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
// Test with minimum required parameters
|
||||
expect(fn() => $api->placePositionTpSlOrder('BTCUSDT', '111'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
// Test with all parameters
|
||||
expect(fn() => $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
'50000',
|
||||
'LAST_PRICE',
|
||||
'45000',
|
||||
'LAST_PRICE'
|
||||
))->not->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
it('can handle special characters in parameters', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
// Test with special characters in position ID
|
||||
expect(fn() => $api->placePositionTpSlOrder('BTCUSDT', 'pos-123-abc'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
// Test with decimal prices
|
||||
expect(fn() => $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
'50000.123',
|
||||
'LAST_PRICE',
|
||||
'45000.456',
|
||||
'LAST_PRICE'
|
||||
))->not->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
it('can handle different combinations of parameters', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
// Test with only TP price
|
||||
expect(fn() => $api->placePositionTpSlOrder('BTCUSDT', '111', '50000'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
// Test with only SL price
|
||||
expect(fn() => $api->placePositionTpSlOrder('BTCUSDT', '111', null, null, '45000'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
// Test with only TP stop type
|
||||
expect(fn() => $api->placePositionTpSlOrder('BTCUSDT', '111', '50000', 'MARK_PRICE'))
|
||||
->not->toThrow(Exception::class);
|
||||
|
||||
// Test with only SL stop type
|
||||
expect(fn() => $api->placePositionTpSlOrder('BTCUSDT', '111', null, null, '45000', 'MARK_PRICE'))
|
||||
->not->toThrow(Exception::class);
|
||||
});
|
||||
|
||||
it('can handle position TP/SL order with mixed stop types', function () {
|
||||
$api = app(PlacePositionTpSlOrderRequestContract::class);
|
||||
|
||||
// Test with different stop types for TP and SL
|
||||
expect(fn() => $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
'50000',
|
||||
'LAST_PRICE',
|
||||
'45000',
|
||||
'MARK_PRICE'
|
||||
))->not->toThrow(Exception::class);
|
||||
|
||||
// Test with opposite stop types
|
||||
expect(fn() => $api->placePositionTpSlOrder(
|
||||
'BTCUSDT',
|
||||
'111',
|
||||
'50000',
|
||||
'MARK_PRICE',
|
||||
'45000',
|
||||
'LAST_PRICE'
|
||||
))->not->toThrow(Exception::class);
|
||||
});
|
||||
Loading…
Reference in New Issue