@gbozee/ultimate 0.0.2-113 → 0.0.2-114
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +334 -349
- package/dist/index.d.ts +91 -16
- package/dist/index.js +334 -349
- package/dist/mcp-server.cjs +334 -349
- package/dist/mcp-server.js +334 -349
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -54723,13 +54723,207 @@ class Strategy {
|
|
|
54723
54723
|
|
|
54724
54724
|
// src/exchanges/binance.ts
|
|
54725
54725
|
var import_binance = __toESM(require_lib2(), 1);
|
|
54726
|
-
|
|
54727
54726
|
// src/types/index.ts
|
|
54728
54727
|
class BaseExchange {
|
|
54729
54728
|
client;
|
|
54729
|
+
getCredentials;
|
|
54730
|
+
proxyAgent;
|
|
54730
54731
|
constructor(client) {
|
|
54731
54732
|
this.client = client;
|
|
54732
54733
|
}
|
|
54734
|
+
async rawCreateLimitPurchaseOrders(payload) {
|
|
54735
|
+
const { symbol, orders, price_places, decimal_places } = payload;
|
|
54736
|
+
return this._createLimitPurchaseOrders({
|
|
54737
|
+
symbol,
|
|
54738
|
+
price_places,
|
|
54739
|
+
decimal_places,
|
|
54740
|
+
orders
|
|
54741
|
+
});
|
|
54742
|
+
}
|
|
54743
|
+
async placeStopOrders(payload) {
|
|
54744
|
+
if (payload.place) {
|
|
54745
|
+
const current_price = await this.getCurrentPrice(payload.symbol);
|
|
54746
|
+
return this._placeStopOrder({
|
|
54747
|
+
symbol: payload.symbol,
|
|
54748
|
+
stop: payload.stop,
|
|
54749
|
+
final_stop: payload.stop,
|
|
54750
|
+
quantity: Math.abs(payload.quantity),
|
|
54751
|
+
kind: payload.kind,
|
|
54752
|
+
cancel: true,
|
|
54753
|
+
is_limit: true,
|
|
54754
|
+
price_places: payload.price_places,
|
|
54755
|
+
decimal_places: payload.decimal_places,
|
|
54756
|
+
current_price
|
|
54757
|
+
});
|
|
54758
|
+
}
|
|
54759
|
+
}
|
|
54760
|
+
async bulkPlaceLimitOrders(payload) {
|
|
54761
|
+
const {
|
|
54762
|
+
orders,
|
|
54763
|
+
kind,
|
|
54764
|
+
decimal_places = "%.3f",
|
|
54765
|
+
price_places = "%.1f",
|
|
54766
|
+
symbol,
|
|
54767
|
+
place = false
|
|
54768
|
+
} = payload;
|
|
54769
|
+
const totalQuantity = orders.reduce((sum, order) => sum + (order.quantity || 0), 0);
|
|
54770
|
+
let runningTotal = to_f2(totalQuantity, decimal_places);
|
|
54771
|
+
let sortedOrders = [...orders].sort((a, b) => (a.entry || 0) - (b.entry || 0));
|
|
54772
|
+
if (kind === "short") {
|
|
54773
|
+
sortedOrders.reverse();
|
|
54774
|
+
}
|
|
54775
|
+
const withCumulative = [];
|
|
54776
|
+
for (const order of sortedOrders) {
|
|
54777
|
+
withCumulative.push({
|
|
54778
|
+
...order,
|
|
54779
|
+
cumulative_quantity: runningTotal
|
|
54780
|
+
});
|
|
54781
|
+
runningTotal -= order.quantity;
|
|
54782
|
+
runningTotal = to_f2(runningTotal, decimal_places);
|
|
54783
|
+
}
|
|
54784
|
+
const positions = await this.getPositionInfo(symbol);
|
|
54785
|
+
const position2 = positions[kind] || {
|
|
54786
|
+
kind,
|
|
54787
|
+
size: 0,
|
|
54788
|
+
entryPrice: 0,
|
|
54789
|
+
symbol
|
|
54790
|
+
};
|
|
54791
|
+
const filteredOrders = withCumulative.filter((order) => (order.cumulative_quantity || 0) > position2.size).map((order) => ({
|
|
54792
|
+
...order,
|
|
54793
|
+
price: order.entry,
|
|
54794
|
+
kind,
|
|
54795
|
+
side: kind.toLowerCase() === "long" ? "buy" : "sell"
|
|
54796
|
+
}));
|
|
54797
|
+
if (filteredOrders.length > 0 && place) {
|
|
54798
|
+
await this.cancelAllOrders(symbol, {
|
|
54799
|
+
type: "limit",
|
|
54800
|
+
kind
|
|
54801
|
+
});
|
|
54802
|
+
await this._createLimitPurchaseOrders({
|
|
54803
|
+
symbol,
|
|
54804
|
+
orders: filteredOrders,
|
|
54805
|
+
price_places,
|
|
54806
|
+
decimal_places
|
|
54807
|
+
});
|
|
54808
|
+
}
|
|
54809
|
+
return filteredOrders;
|
|
54810
|
+
}
|
|
54811
|
+
async get_current_price(symbol) {
|
|
54812
|
+
return await this.getCurrentPrice(symbol);
|
|
54813
|
+
}
|
|
54814
|
+
async getExchangeAccountInfo(options) {
|
|
54815
|
+
const {
|
|
54816
|
+
price_places = "%.1f",
|
|
54817
|
+
decimal_places = "%.3f",
|
|
54818
|
+
account,
|
|
54819
|
+
symbol
|
|
54820
|
+
} = options;
|
|
54821
|
+
return await this.getExchangeInfo({
|
|
54822
|
+
price_places,
|
|
54823
|
+
decimal_places,
|
|
54824
|
+
account,
|
|
54825
|
+
symbol
|
|
54826
|
+
});
|
|
54827
|
+
}
|
|
54828
|
+
async cancelOrders(payload) {
|
|
54829
|
+
return await this._cancelOrders({
|
|
54830
|
+
symbol: payload.symbol,
|
|
54831
|
+
orders: payload.orders.map((x) => ({ orderId: x }))
|
|
54832
|
+
});
|
|
54833
|
+
}
|
|
54834
|
+
async placeTpOrder(payload) {
|
|
54835
|
+
return await this._placeTpOrder({
|
|
54836
|
+
symbol: payload.symbol,
|
|
54837
|
+
tp: payload.take_profit,
|
|
54838
|
+
kind: payload.kind,
|
|
54839
|
+
quantity: payload.quantity,
|
|
54840
|
+
cancel: true,
|
|
54841
|
+
price_places: payload.price_places,
|
|
54842
|
+
decimal_places: payload.decimal_places
|
|
54843
|
+
});
|
|
54844
|
+
}
|
|
54845
|
+
async placeLimitOrder(payload) {
|
|
54846
|
+
return await this.placeLimitOrders({
|
|
54847
|
+
symbol: payload.symbol,
|
|
54848
|
+
orders: [
|
|
54849
|
+
{
|
|
54850
|
+
entry: payload.price,
|
|
54851
|
+
quantity: payload.quantity
|
|
54852
|
+
}
|
|
54853
|
+
],
|
|
54854
|
+
kind: payload.kind,
|
|
54855
|
+
price_places: payload.price_places,
|
|
54856
|
+
decimal_places: payload.decimal_places
|
|
54857
|
+
});
|
|
54858
|
+
}
|
|
54859
|
+
async placeStopOrder(payload) {
|
|
54860
|
+
const current_price = await this.getCurrentPrice(payload.symbol);
|
|
54861
|
+
return await this._placeStopOrder({
|
|
54862
|
+
symbol: payload.symbol,
|
|
54863
|
+
stop: payload.stop,
|
|
54864
|
+
final_stop: payload.stop,
|
|
54865
|
+
quantity: Math.abs(payload.quantity),
|
|
54866
|
+
kind: payload.kind,
|
|
54867
|
+
cancel: true,
|
|
54868
|
+
is_limit: true,
|
|
54869
|
+
price_places: payload.price_places,
|
|
54870
|
+
decimal_places: payload.decimal_places,
|
|
54871
|
+
current_price
|
|
54872
|
+
});
|
|
54873
|
+
}
|
|
54874
|
+
async closePosition(payload) {
|
|
54875
|
+
const { symbol, kind, price_places, decimal_places } = payload;
|
|
54876
|
+
const currentPrice = await this.getCurrentPrice(symbol);
|
|
54877
|
+
return this.placeTpOrder({
|
|
54878
|
+
price_places,
|
|
54879
|
+
decimal_places,
|
|
54880
|
+
symbol,
|
|
54881
|
+
take_profit: currentPrice,
|
|
54882
|
+
kind
|
|
54883
|
+
});
|
|
54884
|
+
}
|
|
54885
|
+
async getAllOpenSymbols() {
|
|
54886
|
+
const response = await this.getAllOpenOrders();
|
|
54887
|
+
return Array.from(new Set(response.map((x) => x.symbol)));
|
|
54888
|
+
}
|
|
54889
|
+
async createLimitPurchaseOrders(payload) {
|
|
54890
|
+
const {
|
|
54891
|
+
orders,
|
|
54892
|
+
kind,
|
|
54893
|
+
decimal_places = "%.3f",
|
|
54894
|
+
price_places = "%.1f",
|
|
54895
|
+
symbol
|
|
54896
|
+
} = payload;
|
|
54897
|
+
return await this._createLimitPurchaseOrders({
|
|
54898
|
+
symbol,
|
|
54899
|
+
price_places,
|
|
54900
|
+
decimal_places,
|
|
54901
|
+
orders: orders.map((order) => ({
|
|
54902
|
+
...order,
|
|
54903
|
+
price: order.entry,
|
|
54904
|
+
kind,
|
|
54905
|
+
side: kind.toLowerCase() === "long" ? "buy" : "sell"
|
|
54906
|
+
}))
|
|
54907
|
+
});
|
|
54908
|
+
}
|
|
54909
|
+
async placeMarketOrder(payload) {
|
|
54910
|
+
const { symbol, kind, quantity, price_places, decimal_places } = payload;
|
|
54911
|
+
const currentPrice = await this.get_current_price(symbol);
|
|
54912
|
+
return this._createLimitPurchaseOrders({
|
|
54913
|
+
symbol,
|
|
54914
|
+
price_places,
|
|
54915
|
+
decimal_places,
|
|
54916
|
+
orders: [
|
|
54917
|
+
{
|
|
54918
|
+
force_market: true,
|
|
54919
|
+
side: kind === "long" ? "buy" : "sell",
|
|
54920
|
+
kind,
|
|
54921
|
+
quantity,
|
|
54922
|
+
price: currentPrice
|
|
54923
|
+
}
|
|
54924
|
+
]
|
|
54925
|
+
});
|
|
54926
|
+
}
|
|
54733
54927
|
async customStopLoss(payload) {
|
|
54734
54928
|
const {
|
|
54735
54929
|
symbol,
|
|
@@ -54768,6 +54962,33 @@ class BaseExchange {
|
|
|
54768
54962
|
decimal_places
|
|
54769
54963
|
});
|
|
54770
54964
|
}
|
|
54965
|
+
async placeBadStopEntry(payload) {
|
|
54966
|
+
const { symbol, orders, price_places, decimal_places } = payload;
|
|
54967
|
+
const openOrders = await this.getOpenOrders({ symbol });
|
|
54968
|
+
const existingBadEntry = openOrders.filter((k) => {
|
|
54969
|
+
if (k.stopPrice > 0) {
|
|
54970
|
+
if (k.kind === "long" && k.price > k.stopPrice || k.kind === "short" && k.price < k.stopPrice) {
|
|
54971
|
+
return true;
|
|
54972
|
+
}
|
|
54973
|
+
return false;
|
|
54974
|
+
}
|
|
54975
|
+
return false;
|
|
54976
|
+
});
|
|
54977
|
+
if (existingBadEntry.length > 0) {
|
|
54978
|
+
console.log("Cancelling existing bad entry");
|
|
54979
|
+
await this._cancelOrders({
|
|
54980
|
+
symbol,
|
|
54981
|
+
orders: existingBadEntry.map((x) => ({ orderId: x.orderId }))
|
|
54982
|
+
});
|
|
54983
|
+
}
|
|
54984
|
+
console.log("Placing new order");
|
|
54985
|
+
return this._createLimitPurchaseOrders({
|
|
54986
|
+
symbol,
|
|
54987
|
+
price_places,
|
|
54988
|
+
decimal_places,
|
|
54989
|
+
orders
|
|
54990
|
+
});
|
|
54991
|
+
}
|
|
54771
54992
|
async analyzeCandlesticks(payload) {
|
|
54772
54993
|
const { symbol } = payload;
|
|
54773
54994
|
const arr = [
|
|
@@ -54818,6 +55039,10 @@ class BaseExchange {
|
|
|
54818
55039
|
minimum_weekly: minimumWeekly
|
|
54819
55040
|
};
|
|
54820
55041
|
}
|
|
55042
|
+
setAccountDetails(payload) {
|
|
55043
|
+
this.getCredentials = payload.getCredentials;
|
|
55044
|
+
this.proxyAgent = payload.proxyAgent;
|
|
55045
|
+
}
|
|
54821
55046
|
}
|
|
54822
55047
|
|
|
54823
55048
|
// src/exchanges/binance.ts
|
|
@@ -55603,98 +55828,22 @@ async function getAllOpenOrders(payload) {
|
|
|
55603
55828
|
class BinanceExchange extends BaseExchange {
|
|
55604
55829
|
client;
|
|
55605
55830
|
main_client;
|
|
55606
|
-
getCredentials;
|
|
55607
|
-
proxyAgent;
|
|
55608
55831
|
constructor(client, main_client) {
|
|
55609
55832
|
super(client);
|
|
55610
55833
|
this.client = client;
|
|
55611
55834
|
this.main_client = main_client;
|
|
55612
55835
|
}
|
|
55613
|
-
|
|
55614
|
-
this.
|
|
55615
|
-
this.proxyAgent = payload.proxyAgent;
|
|
55836
|
+
async getPositionInfo(symbol) {
|
|
55837
|
+
return await getPositionInfo(this.client, symbol);
|
|
55616
55838
|
}
|
|
55617
|
-
async
|
|
55618
|
-
|
|
55619
|
-
const current_price = await this.get_current_price(payload.symbol);
|
|
55620
|
-
return placeStopOrder(this.client, {
|
|
55621
|
-
symbol: payload.symbol,
|
|
55622
|
-
stop: payload.stop,
|
|
55623
|
-
final_stop: payload.stop,
|
|
55624
|
-
quantity: Math.abs(payload.quantity),
|
|
55625
|
-
kind: payload.kind,
|
|
55626
|
-
cancel: true,
|
|
55627
|
-
is_limit: true,
|
|
55628
|
-
price_places: payload.price_places,
|
|
55629
|
-
decimal_places: payload.decimal_places,
|
|
55630
|
-
current_price
|
|
55631
|
-
});
|
|
55632
|
-
}
|
|
55839
|
+
async getCurrentPrice(symbol) {
|
|
55840
|
+
return await getCurrentPrice(this.client, symbol);
|
|
55633
55841
|
}
|
|
55634
|
-
async
|
|
55635
|
-
|
|
55636
|
-
orders,
|
|
55637
|
-
kind,
|
|
55638
|
-
decimal_places = "%.3f",
|
|
55639
|
-
price_places = "%.1f",
|
|
55640
|
-
symbol
|
|
55641
|
-
} = payload;
|
|
55642
|
-
const _orders = orders.map((order) => ({
|
|
55643
|
-
...order,
|
|
55644
|
-
price: order.entry,
|
|
55645
|
-
kind,
|
|
55646
|
-
side: kind.toLowerCase() === "long" ? "buy" : "sell"
|
|
55647
|
-
}));
|
|
55648
|
-
return await createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, _orders);
|
|
55842
|
+
async cancelAllOrders(symbol, payload) {
|
|
55843
|
+
return await cancelAllOrders(this.client, symbol, payload);
|
|
55649
55844
|
}
|
|
55650
|
-
async
|
|
55651
|
-
|
|
55652
|
-
orders,
|
|
55653
|
-
kind,
|
|
55654
|
-
decimal_places = "%.3f",
|
|
55655
|
-
price_places = "%.1f",
|
|
55656
|
-
symbol,
|
|
55657
|
-
place = false
|
|
55658
|
-
} = payload;
|
|
55659
|
-
const totalQuantity = orders.reduce((sum, order) => sum + (order.quantity || 0), 0);
|
|
55660
|
-
let runningTotal = to_f2(totalQuantity, decimal_places);
|
|
55661
|
-
let sortedOrders = [...orders].sort((a, b) => (a.entry || 0) - (b.entry || 0));
|
|
55662
|
-
if (kind === "short") {
|
|
55663
|
-
sortedOrders.reverse();
|
|
55664
|
-
}
|
|
55665
|
-
const withCumulative = [];
|
|
55666
|
-
for (const order of sortedOrders) {
|
|
55667
|
-
withCumulative.push({
|
|
55668
|
-
...order,
|
|
55669
|
-
cumulative_quantity: runningTotal
|
|
55670
|
-
});
|
|
55671
|
-
runningTotal -= order.quantity;
|
|
55672
|
-
runningTotal = to_f2(runningTotal, decimal_places);
|
|
55673
|
-
}
|
|
55674
|
-
const positions = await getPositionInfo(this.client, symbol);
|
|
55675
|
-
const position2 = positions[kind] || {
|
|
55676
|
-
kind,
|
|
55677
|
-
size: 0,
|
|
55678
|
-
entryPrice: 0,
|
|
55679
|
-
symbol
|
|
55680
|
-
};
|
|
55681
|
-
const filteredOrders = withCumulative.filter((order) => (order.cumulative_quantity || 0) > position2.size).map((order) => ({
|
|
55682
|
-
...order,
|
|
55683
|
-
price: order.entry,
|
|
55684
|
-
kind,
|
|
55685
|
-
side: kind.toLowerCase() === "long" ? "buy" : "sell"
|
|
55686
|
-
}));
|
|
55687
|
-
if (filteredOrders.length > 0 && place) {
|
|
55688
|
-
await cancelAllOrders(this.client, symbol, {
|
|
55689
|
-
type: "limit",
|
|
55690
|
-
kind
|
|
55691
|
-
});
|
|
55692
|
-
await createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, filteredOrders);
|
|
55693
|
-
}
|
|
55694
|
-
return filteredOrders;
|
|
55695
|
-
}
|
|
55696
|
-
async get_current_price(symbol) {
|
|
55697
|
-
return await getCurrentPrice(this.client, symbol);
|
|
55845
|
+
async _createLimitPurchaseOrders(payload) {
|
|
55846
|
+
return await createLimitPurchaseOrders(this.client, payload.symbol, payload.price_places, payload.decimal_places, payload.orders);
|
|
55698
55847
|
}
|
|
55699
55848
|
async analyzeCharts(payload) {
|
|
55700
55849
|
return await analyzeCharts({
|
|
@@ -55705,67 +55854,30 @@ class BinanceExchange extends BaseExchange {
|
|
|
55705
55854
|
raw: payload.raw
|
|
55706
55855
|
});
|
|
55707
55856
|
}
|
|
55708
|
-
async
|
|
55709
|
-
const {
|
|
55710
|
-
price_places = "%.1f",
|
|
55711
|
-
decimal_places = "%.3f",
|
|
55712
|
-
account,
|
|
55713
|
-
symbol
|
|
55714
|
-
} = options;
|
|
55857
|
+
async getExchangeInfo(options) {
|
|
55715
55858
|
return await fetchBinanceAccount(this.client, {
|
|
55716
|
-
owner: account.owner,
|
|
55717
|
-
symbol
|
|
55859
|
+
owner: options.account.owner,
|
|
55860
|
+
symbol: options.symbol
|
|
55718
55861
|
}, {
|
|
55719
|
-
price_places,
|
|
55720
|
-
decimal_places
|
|
55862
|
+
price_places: options.price_places,
|
|
55863
|
+
decimal_places: options.decimal_places
|
|
55721
55864
|
});
|
|
55722
55865
|
}
|
|
55723
|
-
async
|
|
55866
|
+
async _cancelOrders(payload) {
|
|
55724
55867
|
return await cancelOrders({
|
|
55725
55868
|
symbol: payload.symbol,
|
|
55726
|
-
orders: payload.orders
|
|
55869
|
+
orders: payload.orders,
|
|
55727
55870
|
custom_client: this.client
|
|
55728
55871
|
});
|
|
55729
55872
|
}
|
|
55730
|
-
async
|
|
55731
|
-
return await placeTpOrder(this.client,
|
|
55732
|
-
symbol: payload.symbol,
|
|
55733
|
-
tp: payload.take_profit,
|
|
55734
|
-
kind: payload.kind,
|
|
55735
|
-
quantity: payload.quantity,
|
|
55736
|
-
cancel: true,
|
|
55737
|
-
price_places: payload.price_places,
|
|
55738
|
-
decimal_places: payload.decimal_places
|
|
55739
|
-
});
|
|
55873
|
+
async _placeTpOrder(payload) {
|
|
55874
|
+
return await placeTpOrder(this.client, payload);
|
|
55740
55875
|
}
|
|
55741
|
-
async
|
|
55742
|
-
return await placeLimitOrders(this.client,
|
|
55743
|
-
symbol: payload.symbol,
|
|
55744
|
-
orders: [
|
|
55745
|
-
{
|
|
55746
|
-
entry: payload.price,
|
|
55747
|
-
quantity: payload.quantity
|
|
55748
|
-
}
|
|
55749
|
-
],
|
|
55750
|
-
kind: payload.kind,
|
|
55751
|
-
price_places: payload.price_places,
|
|
55752
|
-
decimal_places: payload.decimal_places
|
|
55753
|
-
});
|
|
55876
|
+
async placeLimitOrders(payload) {
|
|
55877
|
+
return await placeLimitOrders(this.client, payload);
|
|
55754
55878
|
}
|
|
55755
|
-
async
|
|
55756
|
-
|
|
55757
|
-
return await placeStopOrder(this.client, {
|
|
55758
|
-
symbol: payload.symbol,
|
|
55759
|
-
stop: payload.stop,
|
|
55760
|
-
final_stop: payload.stop,
|
|
55761
|
-
quantity: Math.abs(payload.quantity),
|
|
55762
|
-
kind: payload.kind,
|
|
55763
|
-
cancel: true,
|
|
55764
|
-
is_limit: true,
|
|
55765
|
-
price_places: payload.price_places,
|
|
55766
|
-
decimal_places: payload.decimal_places,
|
|
55767
|
-
current_price
|
|
55768
|
-
});
|
|
55879
|
+
async _placeStopOrder(payload) {
|
|
55880
|
+
return await placeStopOrder(this.client, payload);
|
|
55769
55881
|
}
|
|
55770
55882
|
async setLeverage(payload) {
|
|
55771
55883
|
let maxLeverage = payload.leverage;
|
|
@@ -55859,20 +55971,8 @@ class BinanceExchange extends BaseExchange {
|
|
|
55859
55971
|
const _movers = activeMovers.filter((m) => !toBeDelisted.includes(m.symbol));
|
|
55860
55972
|
return { movers: _movers, delisted };
|
|
55861
55973
|
}
|
|
55862
|
-
async
|
|
55863
|
-
|
|
55864
|
-
const currentPrice = await this.get_current_price(symbol);
|
|
55865
|
-
return this.placeTpOrder({
|
|
55866
|
-
price_places,
|
|
55867
|
-
decimal_places,
|
|
55868
|
-
symbol,
|
|
55869
|
-
take_profit: currentPrice,
|
|
55870
|
-
kind
|
|
55871
|
-
});
|
|
55872
|
-
}
|
|
55873
|
-
async getAllOpenSymbols() {
|
|
55874
|
-
const response = await getAllOpenOrders({ client: this.client });
|
|
55875
|
-
return Array.from(new Set(response.map((x) => x.symbol)));
|
|
55974
|
+
async getAllOpenOrders() {
|
|
55975
|
+
return await getAllOpenOrders({ client: this.client });
|
|
55876
55976
|
}
|
|
55877
55977
|
async getDelistedSpotSymbols() {
|
|
55878
55978
|
if (this.main_client) {
|
|
@@ -55905,49 +56005,9 @@ class BinanceExchange extends BaseExchange {
|
|
|
55905
56005
|
return result;
|
|
55906
56006
|
}
|
|
55907
56007
|
}
|
|
55908
|
-
async placeMarketOrder(payload) {
|
|
55909
|
-
const { symbol, kind, quantity, price_places, decimal_places } = payload;
|
|
55910
|
-
const currentPrice = await this.get_current_price(symbol);
|
|
55911
|
-
return createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, [
|
|
55912
|
-
{
|
|
55913
|
-
force_market: true,
|
|
55914
|
-
side: kind === "long" ? "buy" : "sell",
|
|
55915
|
-
kind,
|
|
55916
|
-
quantity,
|
|
55917
|
-
price: currentPrice
|
|
55918
|
-
}
|
|
55919
|
-
]);
|
|
55920
|
-
}
|
|
55921
|
-
async rawCreateLimitPurchaseOrders(payload) {
|
|
55922
|
-
const { symbol, orders, price_places, decimal_places } = payload;
|
|
55923
|
-
return createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, orders);
|
|
55924
|
-
}
|
|
55925
56008
|
async getOpenOrders(payload) {
|
|
55926
56009
|
return await getOpenOrders(this.client, payload.symbol);
|
|
55927
56010
|
}
|
|
55928
|
-
async placeBadStopEntry(payload) {
|
|
55929
|
-
const { symbol, orders, price_places, decimal_places } = payload;
|
|
55930
|
-
const openOrders = await this.getOpenOrders({ symbol });
|
|
55931
|
-
const existingBadEntry = openOrders.filter((k) => {
|
|
55932
|
-
if (k.stopPrice > 0) {
|
|
55933
|
-
if (k.kind === "long" && k.price > k.stopPrice || k.kind === "short" && k.price < k.stopPrice) {
|
|
55934
|
-
return true;
|
|
55935
|
-
}
|
|
55936
|
-
return false;
|
|
55937
|
-
}
|
|
55938
|
-
return false;
|
|
55939
|
-
});
|
|
55940
|
-
if (existingBadEntry.length > 0) {
|
|
55941
|
-
console.log("Cancelling existing bad entry");
|
|
55942
|
-
await cancelOrders({
|
|
55943
|
-
symbol,
|
|
55944
|
-
orders: existingBadEntry.map((x) => ({ orderId: x.orderId })),
|
|
55945
|
-
custom_client: this.client
|
|
55946
|
-
});
|
|
55947
|
-
}
|
|
55948
|
-
console.log("Placing new order");
|
|
55949
|
-
return createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, orders);
|
|
55950
|
-
}
|
|
55951
56011
|
}
|
|
55952
56012
|
function getPricePlaces(target) {
|
|
55953
56013
|
const numStr = target.toString();
|
|
@@ -56145,10 +56205,11 @@ async function placeStopOrder2(client, payload) {
|
|
|
56145
56205
|
kind: payload.kind
|
|
56146
56206
|
});
|
|
56147
56207
|
}
|
|
56208
|
+
const spread = 1.00005;
|
|
56148
56209
|
const order = {
|
|
56149
56210
|
kind: payload.kind,
|
|
56150
56211
|
side: payload.kind === "long" ? "sell" : "buy",
|
|
56151
|
-
price: payload.stop,
|
|
56212
|
+
price: payload.kind === "long" ? payload.stop * spread ** -1 : payload.stop * spread,
|
|
56152
56213
|
quantity: payload.quantity,
|
|
56153
56214
|
stop: payload.final_stop,
|
|
56154
56215
|
is_market: !payload.is_limit
|
|
@@ -56444,6 +56505,28 @@ async function analyzeCharts2(params) {
|
|
|
56444
56505
|
}
|
|
56445
56506
|
return finalPairs;
|
|
56446
56507
|
}
|
|
56508
|
+
async function getAllOpenOrders2(payload) {
|
|
56509
|
+
const { client, currency = "USDT" } = payload;
|
|
56510
|
+
const response = await client.getActiveOrders({
|
|
56511
|
+
category: "linear",
|
|
56512
|
+
openOnly: 0,
|
|
56513
|
+
settleCoin: currency
|
|
56514
|
+
});
|
|
56515
|
+
let cursor = response.result.nextPageCursor;
|
|
56516
|
+
const orders = response.result.list || [];
|
|
56517
|
+
while (Boolean(cursor)) {
|
|
56518
|
+
const nextResponse = await client.getActiveOrders({
|
|
56519
|
+
category: "linear",
|
|
56520
|
+
openOnly: 0,
|
|
56521
|
+
settleCoin: currency,
|
|
56522
|
+
cursor
|
|
56523
|
+
});
|
|
56524
|
+
orders.push(...nextResponse.result.list);
|
|
56525
|
+
cursor = nextResponse.result.nextPageCursor;
|
|
56526
|
+
console.log("getAllOpenOrders cursor", cursor);
|
|
56527
|
+
}
|
|
56528
|
+
return orders;
|
|
56529
|
+
}
|
|
56447
56530
|
|
|
56448
56531
|
class BybitExchange extends BaseExchange {
|
|
56449
56532
|
client;
|
|
@@ -56453,68 +56536,16 @@ class BybitExchange extends BaseExchange {
|
|
|
56453
56536
|
this.client = client;
|
|
56454
56537
|
this.main_client = main_client;
|
|
56455
56538
|
}
|
|
56456
|
-
async
|
|
56457
|
-
|
|
56458
|
-
return placeStopOrder2(this.client, {
|
|
56459
|
-
symbol: payload.symbol,
|
|
56460
|
-
stop: payload.stop,
|
|
56461
|
-
final_stop: payload.stop,
|
|
56462
|
-
quantity: Math.abs(payload.quantity),
|
|
56463
|
-
kind: payload.kind,
|
|
56464
|
-
cancel: true,
|
|
56465
|
-
is_limit: true,
|
|
56466
|
-
price_places: payload.price_places,
|
|
56467
|
-
decimal_places: payload.decimal_places
|
|
56468
|
-
});
|
|
56469
|
-
}
|
|
56539
|
+
async getPositionInfo(symbol) {
|
|
56540
|
+
return await getPositionInfo2(this.client, symbol);
|
|
56470
56541
|
}
|
|
56471
|
-
async
|
|
56472
|
-
|
|
56473
|
-
orders,
|
|
56474
|
-
kind,
|
|
56475
|
-
decimal_places = "%.3f",
|
|
56476
|
-
price_places = "%.1f",
|
|
56477
|
-
symbol,
|
|
56478
|
-
place = false
|
|
56479
|
-
} = payload;
|
|
56480
|
-
const totalQuantity = orders.reduce((sum, order) => sum + (order.quantity || 0), 0);
|
|
56481
|
-
let runningTotal = to_f2(totalQuantity, decimal_places);
|
|
56482
|
-
let sortedOrders = [...orders].sort((a, b) => (a.entry || 0) - (b.entry || 0));
|
|
56483
|
-
if (kind === "short") {
|
|
56484
|
-
sortedOrders.reverse();
|
|
56485
|
-
}
|
|
56486
|
-
const withCumulative = [];
|
|
56487
|
-
for (const order of sortedOrders) {
|
|
56488
|
-
withCumulative.push({
|
|
56489
|
-
...order,
|
|
56490
|
-
cumulative_quantity: runningTotal
|
|
56491
|
-
});
|
|
56492
|
-
runningTotal -= order.quantity;
|
|
56493
|
-
runningTotal = to_f2(runningTotal, decimal_places);
|
|
56494
|
-
}
|
|
56495
|
-
const positions = await getPositionInfo2(this.client, symbol);
|
|
56496
|
-
const position2 = positions[kind] || {
|
|
56497
|
-
kind,
|
|
56498
|
-
size: 0,
|
|
56499
|
-
entryPrice: 0,
|
|
56500
|
-
symbol
|
|
56501
|
-
};
|
|
56502
|
-
const filteredOrders = withCumulative.filter((order) => (order.cumulative_quantity || 0) > position2.size).map((order) => ({
|
|
56503
|
-
...order,
|
|
56504
|
-
price: order.entry,
|
|
56505
|
-
kind,
|
|
56506
|
-
side: kind.toLowerCase() === "long" ? "buy" : "sell"
|
|
56507
|
-
}));
|
|
56508
|
-
if (filteredOrders.length > 0 && place) {
|
|
56509
|
-
await cancelAllOrders2(this.client, symbol, {
|
|
56510
|
-
type: "limit",
|
|
56511
|
-
kind
|
|
56512
|
-
});
|
|
56513
|
-
await createLimitPurchaseOrders2(this.client, symbol, price_places, decimal_places, filteredOrders);
|
|
56514
|
-
}
|
|
56515
|
-
return filteredOrders;
|
|
56542
|
+
async cancelAllOrders(symbol, payload) {
|
|
56543
|
+
return await cancelAllOrders2(this.client, symbol, payload);
|
|
56516
56544
|
}
|
|
56517
|
-
async
|
|
56545
|
+
async _createLimitPurchaseOrders(payload) {
|
|
56546
|
+
return await createLimitPurchaseOrders2(this.client, payload.symbol, payload.price_places, payload.decimal_places, payload.orders);
|
|
56547
|
+
}
|
|
56548
|
+
async getCurrentPrice(symbol) {
|
|
56518
56549
|
return await getCurrentPrice2(this.client, symbol);
|
|
56519
56550
|
}
|
|
56520
56551
|
async analyzeCharts(payload) {
|
|
@@ -56526,60 +56557,30 @@ class BybitExchange extends BaseExchange {
|
|
|
56526
56557
|
raw: payload.raw || false
|
|
56527
56558
|
});
|
|
56528
56559
|
}
|
|
56529
|
-
async
|
|
56530
|
-
const {
|
|
56531
|
-
price_places = "%.1f",
|
|
56532
|
-
decimal_places = "%.3f",
|
|
56533
|
-
account,
|
|
56534
|
-
symbol
|
|
56535
|
-
} = options;
|
|
56560
|
+
async getExchangeInfo(options) {
|
|
56536
56561
|
return await fetchBybitAccount(this.client, {
|
|
56537
|
-
owner: account.owner,
|
|
56538
|
-
symbol
|
|
56562
|
+
owner: options.account.owner,
|
|
56563
|
+
symbol: options.symbol
|
|
56539
56564
|
}, {
|
|
56540
|
-
price_places,
|
|
56541
|
-
decimal_places
|
|
56565
|
+
price_places: options.price_places,
|
|
56566
|
+
decimal_places: options.decimal_places
|
|
56542
56567
|
});
|
|
56543
56568
|
}
|
|
56544
|
-
async
|
|
56569
|
+
async _cancelOrders(payload) {
|
|
56545
56570
|
return await cancelOrders2({
|
|
56546
56571
|
symbol: payload.symbol,
|
|
56547
|
-
orders: payload.orders
|
|
56572
|
+
orders: payload.orders,
|
|
56548
56573
|
custom_client: this.client
|
|
56549
56574
|
});
|
|
56550
56575
|
}
|
|
56551
|
-
async
|
|
56552
|
-
return await placeTpOrder2(this.client,
|
|
56553
|
-
symbol: payload.symbol,
|
|
56554
|
-
tp: payload.take_profit,
|
|
56555
|
-
kind: payload.kind,
|
|
56556
|
-
cancel: true
|
|
56557
|
-
});
|
|
56576
|
+
async _placeTpOrder(payload) {
|
|
56577
|
+
return await placeTpOrder2(this.client, payload);
|
|
56558
56578
|
}
|
|
56559
|
-
async
|
|
56560
|
-
return await placeLimitOrders2(this.client,
|
|
56561
|
-
symbol: payload.symbol,
|
|
56562
|
-
orders: [
|
|
56563
|
-
{
|
|
56564
|
-
entry: payload.price,
|
|
56565
|
-
quantity: payload.quantity
|
|
56566
|
-
}
|
|
56567
|
-
],
|
|
56568
|
-
kind: payload.kind
|
|
56569
|
-
});
|
|
56579
|
+
async placeLimitOrders(payload) {
|
|
56580
|
+
return await placeLimitOrders2(this.client, payload);
|
|
56570
56581
|
}
|
|
56571
|
-
async
|
|
56572
|
-
return await placeStopOrder2(this.client,
|
|
56573
|
-
symbol: payload.symbol,
|
|
56574
|
-
stop: payload.stop,
|
|
56575
|
-
final_stop: payload.stop,
|
|
56576
|
-
quantity: Math.abs(payload.quantity),
|
|
56577
|
-
kind: payload.kind,
|
|
56578
|
-
cancel: true,
|
|
56579
|
-
is_limit: true,
|
|
56580
|
-
price_places: payload.price_places,
|
|
56581
|
-
decimal_places: payload.decimal_places
|
|
56582
|
-
});
|
|
56582
|
+
async _placeStopOrder(payload) {
|
|
56583
|
+
return await placeStopOrder2(this.client, payload);
|
|
56583
56584
|
}
|
|
56584
56585
|
async setLeverage(payload) {
|
|
56585
56586
|
return await this.client.setLeverage({
|
|
@@ -56593,40 +56594,18 @@ class BybitExchange extends BaseExchange {
|
|
|
56593
56594
|
}
|
|
56594
56595
|
async checkDelistedMovers(payload) {
|
|
56595
56596
|
}
|
|
56596
|
-
async
|
|
56597
|
-
|
|
56598
|
-
|
|
56599
|
-
return [];
|
|
56597
|
+
async getAllOpenOrders() {
|
|
56598
|
+
const result = await getAllOpenOrders2({ client: this.client });
|
|
56599
|
+
return result;
|
|
56600
56600
|
}
|
|
56601
56601
|
async getOpenPositions() {
|
|
56602
56602
|
return [];
|
|
56603
56603
|
}
|
|
56604
|
-
async createLimitPurchaseOrders(payload) {
|
|
56605
|
-
const {
|
|
56606
|
-
orders,
|
|
56607
|
-
kind,
|
|
56608
|
-
decimal_places = "%.3f",
|
|
56609
|
-
price_places = "%.1f",
|
|
56610
|
-
symbol
|
|
56611
|
-
} = payload;
|
|
56612
|
-
return await createLimitPurchaseOrders2(this.client, symbol, price_places, decimal_places, orders.map((order) => ({
|
|
56613
|
-
...order,
|
|
56614
|
-
price: order.entry,
|
|
56615
|
-
kind,
|
|
56616
|
-
side: kind.toLowerCase() === "long" ? "buy" : "sell"
|
|
56617
|
-
})));
|
|
56618
|
-
}
|
|
56619
56604
|
async getDelistedSpotSymbols() {
|
|
56620
56605
|
return [];
|
|
56621
56606
|
}
|
|
56622
56607
|
async crossAccountTransfer(payload) {
|
|
56623
56608
|
}
|
|
56624
|
-
async placeMarketOrder(payload) {
|
|
56625
|
-
}
|
|
56626
|
-
async rawCreateLimitPurchaseOrders(payload) {
|
|
56627
|
-
const { symbol, orders, price_places, decimal_places } = payload;
|
|
56628
|
-
return createLimitPurchaseOrders2(this.client, symbol, price_places, decimal_places, orders);
|
|
56629
|
-
}
|
|
56630
56609
|
getOpenOrders(payload) {
|
|
56631
56610
|
return getOpenOrders2(this.client, payload.symbol);
|
|
56632
56611
|
}
|
|
@@ -58062,6 +58041,9 @@ class ExchangeAccount {
|
|
|
58062
58041
|
long_config,
|
|
58063
58042
|
short_config
|
|
58064
58043
|
});
|
|
58044
|
+
if (!long_config || !short_config) {
|
|
58045
|
+
return null;
|
|
58046
|
+
}
|
|
58065
58047
|
let long_target_pnl = payload.kind == "long" ? payload.target_pnl : 0;
|
|
58066
58048
|
let short_target_pnl = payload.kind == "short" ? payload.target_pnl : 0;
|
|
58067
58049
|
const long_sell_ratio = long_config.sell_ratio || long_position?.sell_ratio;
|
|
@@ -58186,7 +58168,7 @@ class ExchangeAccount {
|
|
|
58186
58168
|
});
|
|
58187
58169
|
const long_pause_tp = long_config?.pause_tp;
|
|
58188
58170
|
const short_pause_tp = short_config?.pause_tp;
|
|
58189
|
-
if (payload.trigger && !long_pause_tp && !short_pause_tp) {
|
|
58171
|
+
if (payload.trigger && !long_pause_tp && !short_pause_tp && config2) {
|
|
58190
58172
|
return await this.reduceMajorPositionEntry({
|
|
58191
58173
|
symbol,
|
|
58192
58174
|
long: config2.long,
|
|
@@ -58750,15 +58732,15 @@ class ExchangeAccount {
|
|
|
58750
58732
|
}
|
|
58751
58733
|
async buildOppositeTrades(payload) {
|
|
58752
58734
|
const { symbol, kind, place, place_symbol } = payload;
|
|
58753
|
-
const
|
|
58735
|
+
const strategy2 = await this.runSimulation({
|
|
58754
58736
|
symbol,
|
|
58755
58737
|
kind,
|
|
58756
58738
|
raw: true
|
|
58757
58739
|
});
|
|
58758
58740
|
try {
|
|
58759
|
-
const result =
|
|
58741
|
+
const result = strategy2.generateOppositeTrades({
|
|
58760
58742
|
kind,
|
|
58761
|
-
avg_entry:
|
|
58743
|
+
avg_entry: strategy2.position[kind].avg_price
|
|
58762
58744
|
});
|
|
58763
58745
|
if (place && result?.kind) {
|
|
58764
58746
|
const _symbol = place_symbol || symbol;
|
|
@@ -58809,7 +58791,7 @@ class ExchangeAccount {
|
|
|
58809
58791
|
reduce_ratio,
|
|
58810
58792
|
global_config: symbol_config
|
|
58811
58793
|
};
|
|
58812
|
-
const
|
|
58794
|
+
const strategy2 = new Strategy({
|
|
58813
58795
|
long: {
|
|
58814
58796
|
entry: long_position.entry,
|
|
58815
58797
|
quantity: long_position.quantity,
|
|
@@ -58825,9 +58807,9 @@ class ExchangeAccount {
|
|
|
58825
58807
|
config: strategy_config
|
|
58826
58808
|
});
|
|
58827
58809
|
if (raw) {
|
|
58828
|
-
return
|
|
58810
|
+
return strategy2;
|
|
58829
58811
|
}
|
|
58830
|
-
return
|
|
58812
|
+
return strategy2.runIterations({
|
|
58831
58813
|
iterations,
|
|
58832
58814
|
kind
|
|
58833
58815
|
});
|
|
@@ -59516,31 +59498,31 @@ class ExchangeAccount {
|
|
|
59516
59498
|
if (!focus_position) {
|
|
59517
59499
|
return;
|
|
59518
59500
|
}
|
|
59519
|
-
const
|
|
59520
|
-
if (!
|
|
59501
|
+
const strategy2 = focus_position?.expand?.account_strategy;
|
|
59502
|
+
if (!strategy2) {
|
|
59521
59503
|
return;
|
|
59522
59504
|
}
|
|
59523
|
-
const risk =
|
|
59524
|
-
const kind =
|
|
59525
|
-
const support =
|
|
59526
|
-
const resistance =
|
|
59505
|
+
const risk = strategy2.risk;
|
|
59506
|
+
const kind = strategy2.kind;
|
|
59507
|
+
const support = strategy2.support;
|
|
59508
|
+
const resistance = strategy2.resistance;
|
|
59527
59509
|
console.log("Getting long and short positions for ", symbol);
|
|
59528
59510
|
const long_position = positions.find((k) => k.kind === "long");
|
|
59529
59511
|
const short_position = positions.find((k) => k.kind === "short");
|
|
59530
59512
|
console.log("Getting focus position for ", symbol, kind);
|
|
59531
59513
|
const reverse_position = kind === "long" ? short_position : long_position;
|
|
59532
|
-
if (
|
|
59533
|
-
reward_factor =
|
|
59514
|
+
if (strategy2.max_reward_factor === 0) {
|
|
59515
|
+
reward_factor = strategy2.reward_factor;
|
|
59534
59516
|
}
|
|
59535
|
-
if (focus_position.avg_qty >= focus_position.quantity &&
|
|
59536
|
-
if (
|
|
59517
|
+
if (focus_position.avg_qty >= focus_position.quantity && strategy2.max_reward_factor) {
|
|
59518
|
+
if (strategy2.dynamic) {
|
|
59537
59519
|
const quantity_ratio = focus_position.quantity / focus_position.avg_qty;
|
|
59538
|
-
reward_factor = to_f2(quantity_ratio ** 2 *
|
|
59520
|
+
reward_factor = to_f2(quantity_ratio ** 2 * strategy2.max_reward_factor, "%.2f");
|
|
59539
59521
|
} else {
|
|
59540
|
-
reward_factor = to_f2(focus_position.quantity *
|
|
59522
|
+
reward_factor = to_f2(focus_position.quantity * strategy2.max_reward_factor / focus_position.avg_qty, "%.4f");
|
|
59541
59523
|
}
|
|
59542
59524
|
} else {
|
|
59543
|
-
reward_factor =
|
|
59525
|
+
reward_factor = strategy2.reward_factor;
|
|
59544
59526
|
}
|
|
59545
59527
|
console.log("Getting entry and stop for ", symbol, kind);
|
|
59546
59528
|
const entry = kind === "long" ? resistance : support;
|
|
@@ -59554,7 +59536,7 @@ class ExchangeAccount {
|
|
|
59554
59536
|
symbol
|
|
59555
59537
|
});
|
|
59556
59538
|
console.log("Computing risk reward for ", symbol, kind);
|
|
59557
|
-
const risk_reward =
|
|
59539
|
+
const risk_reward = strategy2.risk_reward || computeRiskReward({
|
|
59558
59540
|
app_config: initial_app_config,
|
|
59559
59541
|
entry: initial_app_config.entry,
|
|
59560
59542
|
stop: initial_app_config.stop,
|
|
@@ -59687,7 +59669,7 @@ class ExchangeAccount {
|
|
|
59687
59669
|
const max_size = app_config.max_size * 0.98;
|
|
59688
59670
|
if (reverse_config.threshold_qty !== max_size) {
|
|
59689
59671
|
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59690
|
-
follow:
|
|
59672
|
+
follow: strategy2.follow,
|
|
59691
59673
|
threshold_qty: max_size
|
|
59692
59674
|
});
|
|
59693
59675
|
}
|
|
@@ -59761,8 +59743,8 @@ class ExchangeAccount {
|
|
|
59761
59743
|
}
|
|
59762
59744
|
const reverse_kind = focus_position.kind === "long" ? "short" : "long";
|
|
59763
59745
|
const reverse_position = positions.find((k) => k.kind === reverse_kind);
|
|
59764
|
-
const
|
|
59765
|
-
if (!
|
|
59746
|
+
const strategy2 = focus_position?.expand?.account_strategy;
|
|
59747
|
+
if (!strategy2) {
|
|
59766
59748
|
return;
|
|
59767
59749
|
}
|
|
59768
59750
|
return computeProfitDetail({
|
|
@@ -59775,9 +59757,9 @@ class ExchangeAccount {
|
|
|
59775
59757
|
},
|
|
59776
59758
|
pnl: focus_position.target_pnl,
|
|
59777
59759
|
strategy: {
|
|
59778
|
-
reward_factor:
|
|
59779
|
-
risk:
|
|
59780
|
-
max_reward_factor:
|
|
59760
|
+
reward_factor: strategy2.reward_factor,
|
|
59761
|
+
risk: strategy2.risk,
|
|
59762
|
+
max_reward_factor: strategy2.max_reward_factor
|
|
59781
59763
|
},
|
|
59782
59764
|
reduce_position: {
|
|
59783
59765
|
kind: reduce_position.kind,
|
|
@@ -60023,6 +60005,9 @@ class App {
|
|
|
60023
60005
|
owner: exchange.owner,
|
|
60024
60006
|
exchange: exchange.exchange
|
|
60025
60007
|
});
|
|
60008
|
+
if (exchange.exchange === "bybit" && symbol === "BTCUSDC") {
|
|
60009
|
+
continue;
|
|
60010
|
+
}
|
|
60026
60011
|
await exchange_account.placeProfitAndStop({
|
|
60027
60012
|
symbol,
|
|
60028
60013
|
trigger: true,
|
|
@@ -60117,11 +60102,11 @@ class App {
|
|
|
60117
60102
|
}
|
|
60118
60103
|
async runDbStrategyAccounts(callback) {
|
|
60119
60104
|
const strategies = await this.app_db.getRunningAccountStrategies();
|
|
60120
|
-
for (const
|
|
60121
|
-
console.log("Running strategy for ",
|
|
60105
|
+
for (const strategy2 of strategies) {
|
|
60106
|
+
console.log("Running strategy for ", strategy2.symbol, "for account", strategy2.expand.account.owner, strategy2.expand.account.exchange);
|
|
60122
60107
|
await callback({
|
|
60123
|
-
symbol:
|
|
60124
|
-
account:
|
|
60108
|
+
symbol: strategy2.symbol,
|
|
60109
|
+
account: strategy2.expand.account
|
|
60125
60110
|
});
|
|
60126
60111
|
}
|
|
60127
60112
|
}
|