@gbozee/ultimate 0.0.2-79 → 0.0.2-83
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/frontend-index.js +1 -1
- package/dist/index.cjs +175 -33
- package/dist/index.d.ts +96 -10
- package/dist/index.js +175 -33
- package/dist/mcp-server.cjs +181 -39
- package/dist/mcp-server.js +181 -39
- package/package.json +1 -1
package/dist/frontend-index.js
CHANGED
|
@@ -610,7 +610,7 @@ class Signal {
|
|
|
610
610
|
new_stop
|
|
611
611
|
};
|
|
612
612
|
});
|
|
613
|
-
if (greater_than_min_size.length !==
|
|
613
|
+
if (greater_than_min_size.length !== total_orders.length) {
|
|
614
614
|
payload = greater_than_min_size.concat(less_than_min_size);
|
|
615
615
|
}
|
|
616
616
|
return payload;
|
package/dist/index.cjs
CHANGED
|
@@ -53114,7 +53114,7 @@ class Signal {
|
|
|
53114
53114
|
new_stop
|
|
53115
53115
|
};
|
|
53116
53116
|
});
|
|
53117
|
-
if (greater_than_min_size.length !==
|
|
53117
|
+
if (greater_than_min_size.length !== total_orders.length) {
|
|
53118
53118
|
payload = greater_than_min_size.concat(less_than_min_size);
|
|
53119
53119
|
}
|
|
53120
53120
|
return payload;
|
|
@@ -58770,7 +58770,6 @@ async function getExchangeAccount(payload) {
|
|
|
58770
58770
|
app_db
|
|
58771
58771
|
});
|
|
58772
58772
|
}
|
|
58773
|
-
|
|
58774
58773
|
// src/app.ts
|
|
58775
58774
|
class App {
|
|
58776
58775
|
app_db;
|
|
@@ -58829,37 +58828,6 @@ class App {
|
|
|
58829
58828
|
stop: payload.stop
|
|
58830
58829
|
});
|
|
58831
58830
|
}
|
|
58832
|
-
async updateReduceRatio(payload) {
|
|
58833
|
-
const { symbol } = payload;
|
|
58834
|
-
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
58835
|
-
const positions = await exchange_account.syncAccount({
|
|
58836
|
-
as_view: true,
|
|
58837
|
-
symbol
|
|
58838
|
-
});
|
|
58839
|
-
const active_account = await exchange_account.getActiveAccount({
|
|
58840
|
-
symbol
|
|
58841
|
-
});
|
|
58842
|
-
const long_position = active_account.position.long;
|
|
58843
|
-
const short_position = active_account.position.short;
|
|
58844
|
-
const long_db_position = positions.find((p) => p.kind === "long");
|
|
58845
|
-
const short_db_position = positions.find((p) => p.kind === "short");
|
|
58846
|
-
const balance = active_account.usd_balance || 0;
|
|
58847
|
-
const long_liquidation = long_db_position.avg_price * long_db_position.avg_qty / long_db_position.leverage - balance / long_db_position.avg_qty + long_db_position.avg_price;
|
|
58848
|
-
const short_liquidation = -(short_db_position.avg_price * short_db_position.avg_qty / short_db_position.leverage) + balance / short_db_position.avg_qty + short_db_position.avg_price;
|
|
58849
|
-
long_position.avg_liquidation = to_f2(long_liquidation, "%.3f");
|
|
58850
|
-
short_position.avg_liquidation = to_f2(short_liquidation, "%.3f");
|
|
58851
|
-
const long_ratio = Math.max(long_position.avg_liquidation, long_position.avg_entry) / Math.min(long_position.avg_liquidation, long_position.avg_entry) - 1;
|
|
58852
|
-
const short_ratio = Math.max(short_position.avg_liquidation, short_position.avg_entry) / Math.min(short_position.avg_liquidation, short_position.avg_entry) - 1;
|
|
58853
|
-
long_position.liquidation_ratio = to_f2(long_ratio, "%.3f") * 100;
|
|
58854
|
-
short_position.liquidation_ratio = to_f2(short_ratio, "%.3f") * 100;
|
|
58855
|
-
return {
|
|
58856
|
-
long_position,
|
|
58857
|
-
short_position,
|
|
58858
|
-
long_db_position,
|
|
58859
|
-
short_db_position,
|
|
58860
|
-
balance: active_account.usd_balance
|
|
58861
|
-
};
|
|
58862
|
-
}
|
|
58863
58831
|
async getWindingDownMarkets() {
|
|
58864
58832
|
return await this.app_db.getWindingDownMarkets();
|
|
58865
58833
|
}
|
|
@@ -59069,6 +59037,180 @@ class App {
|
|
|
59069
59037
|
});
|
|
59070
59038
|
return result;
|
|
59071
59039
|
}
|
|
59040
|
+
async profitWithinGapStrategy(payload) {
|
|
59041
|
+
const {
|
|
59042
|
+
account,
|
|
59043
|
+
symbol,
|
|
59044
|
+
kind,
|
|
59045
|
+
risk,
|
|
59046
|
+
resistance,
|
|
59047
|
+
support,
|
|
59048
|
+
reward_factor = 1
|
|
59049
|
+
} = payload;
|
|
59050
|
+
const exchange_account = await this.getExchangeAccount(account);
|
|
59051
|
+
console.log("Getting entry and stop for ", symbol, kind);
|
|
59052
|
+
const entry = kind === "long" ? resistance : support;
|
|
59053
|
+
const stop = kind === "long" ? support : resistance;
|
|
59054
|
+
console.log("Building app config for ", symbol, kind);
|
|
59055
|
+
const initial_app_config = await exchange_account.buildAppConfig({
|
|
59056
|
+
entry,
|
|
59057
|
+
stop,
|
|
59058
|
+
risk_reward: 199,
|
|
59059
|
+
risk,
|
|
59060
|
+
symbol
|
|
59061
|
+
});
|
|
59062
|
+
console.log("Computing risk reward for ", symbol, kind);
|
|
59063
|
+
const risk_reward = computeRiskReward({
|
|
59064
|
+
app_config: initial_app_config,
|
|
59065
|
+
entry: initial_app_config.entry,
|
|
59066
|
+
stop: initial_app_config.stop,
|
|
59067
|
+
risk_per_trade: initial_app_config.risk_per_trade
|
|
59068
|
+
});
|
|
59069
|
+
console.log("Re-computing app config for ", symbol, kind);
|
|
59070
|
+
const { entries, last_value, ...app_config } = await exchange_account.buildAppConfig({
|
|
59071
|
+
entry: initial_app_config.entry,
|
|
59072
|
+
stop: initial_app_config.stop,
|
|
59073
|
+
risk_reward,
|
|
59074
|
+
risk,
|
|
59075
|
+
symbol
|
|
59076
|
+
});
|
|
59077
|
+
console.log("Computing profit percent for ", symbol, kind);
|
|
59078
|
+
const pnl = reward_factor * risk;
|
|
59079
|
+
const profit_percent = to_f2(pnl * 100 / (last_value.avg_entry * last_value.avg_size), "%.4f");
|
|
59080
|
+
let config2 = {
|
|
59081
|
+
entry,
|
|
59082
|
+
stop,
|
|
59083
|
+
risk,
|
|
59084
|
+
risk_reward,
|
|
59085
|
+
profit_percent
|
|
59086
|
+
};
|
|
59087
|
+
console.log("Saving new config for ", symbol, kind);
|
|
59088
|
+
const data = await exchange_account.getPositionConfig({
|
|
59089
|
+
symbol,
|
|
59090
|
+
kind,
|
|
59091
|
+
params: config2
|
|
59092
|
+
});
|
|
59093
|
+
console.log("Checking orders to place for ", symbol, kind);
|
|
59094
|
+
const orders_to_place = await exchange_account.placeTrade({
|
|
59095
|
+
symbol,
|
|
59096
|
+
raw: true,
|
|
59097
|
+
kind,
|
|
59098
|
+
place: false
|
|
59099
|
+
});
|
|
59100
|
+
config2 = {
|
|
59101
|
+
...config2,
|
|
59102
|
+
...data
|
|
59103
|
+
};
|
|
59104
|
+
console.log("Fetching positions for ", symbol);
|
|
59105
|
+
const positions = await exchange_account.syncAccount({
|
|
59106
|
+
symbol,
|
|
59107
|
+
as_view: true
|
|
59108
|
+
});
|
|
59109
|
+
console.log("Getting long and short positions for ", symbol);
|
|
59110
|
+
const long_position = positions.find((k) => k.kind === "long");
|
|
59111
|
+
const short_position = positions.find((k) => k.kind === "short");
|
|
59112
|
+
console.log("Getting focus position for ", symbol, kind);
|
|
59113
|
+
const focus_position = kind === "long" ? long_position : short_position;
|
|
59114
|
+
const reverse_position = kind === "long" ? short_position : long_position;
|
|
59115
|
+
let reverse_action = null;
|
|
59116
|
+
let reverse_orders_to_buy = [];
|
|
59117
|
+
let reverse_config = null;
|
|
59118
|
+
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
59119
|
+
if (focus_position.quantity > 0) {
|
|
59120
|
+
console.log("Getting details for ", reverse_position.kind);
|
|
59121
|
+
reverse_action = await exchange_account.buildOppositeTrades({
|
|
59122
|
+
symbol,
|
|
59123
|
+
kind
|
|
59124
|
+
});
|
|
59125
|
+
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
59126
|
+
await exchange_account.getPositionConfig({
|
|
59127
|
+
symbol,
|
|
59128
|
+
kind: reverse_action.kind,
|
|
59129
|
+
params: {
|
|
59130
|
+
entry: reverse_action.entry,
|
|
59131
|
+
stop: reverse_action.stop,
|
|
59132
|
+
risk: reverse_action.risk_per_trade,
|
|
59133
|
+
profit_percent: reverse_action.profit_percent,
|
|
59134
|
+
risk_reward: reverse_action.risk_reward
|
|
59135
|
+
}
|
|
59136
|
+
});
|
|
59137
|
+
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
59138
|
+
const reverse_app_config = await exchange_account.buildAppConfig({
|
|
59139
|
+
entry: reverse_action.entry,
|
|
59140
|
+
stop: reverse_action.stop,
|
|
59141
|
+
risk_reward: reverse_action.risk_reward,
|
|
59142
|
+
risk: reverse_action.risk_per_trade,
|
|
59143
|
+
symbol
|
|
59144
|
+
});
|
|
59145
|
+
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
59146
|
+
reverse_orders_to_buy = await exchange_account.placeTrade({
|
|
59147
|
+
symbol,
|
|
59148
|
+
raw: true,
|
|
59149
|
+
kind: reverse_action.kind,
|
|
59150
|
+
place: false
|
|
59151
|
+
});
|
|
59152
|
+
let _reverse_config = {
|
|
59153
|
+
avg: reverse_action.avg,
|
|
59154
|
+
entry: reverse_action.entry,
|
|
59155
|
+
stop: reverse_action.stop,
|
|
59156
|
+
risk_per_trade: reverse_action.risk_per_trade,
|
|
59157
|
+
profit_percent: reverse_action.profit_percent,
|
|
59158
|
+
risk_reward: reverse_action.risk_reward
|
|
59159
|
+
};
|
|
59160
|
+
if (reverse_orders_to_buy.length > 0) {
|
|
59161
|
+
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
59162
|
+
let existing = await exchange_account.placeOppositeTradeAction({
|
|
59163
|
+
symbol,
|
|
59164
|
+
kind: reverse_action.kind,
|
|
59165
|
+
data: _reverse_config
|
|
59166
|
+
});
|
|
59167
|
+
_reverse_config = {
|
|
59168
|
+
...existing,
|
|
59169
|
+
..._reverse_config
|
|
59170
|
+
};
|
|
59171
|
+
}
|
|
59172
|
+
reverse_config = _reverse_config;
|
|
59173
|
+
}
|
|
59174
|
+
if (!reverse_config?.id) {
|
|
59175
|
+
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
59176
|
+
reverse_config = await exchange_account.getPositionConfig({
|
|
59177
|
+
symbol,
|
|
59178
|
+
kind: reverse_action.kind
|
|
59179
|
+
});
|
|
59180
|
+
}
|
|
59181
|
+
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
59182
|
+
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
59183
|
+
const max_size = app_config.max_size * 0.98;
|
|
59184
|
+
if (reverse_config.threshold_qty !== max_size) {
|
|
59185
|
+
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59186
|
+
follow: true,
|
|
59187
|
+
threshold_qty: max_size
|
|
59188
|
+
});
|
|
59189
|
+
}
|
|
59190
|
+
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
59191
|
+
} else {
|
|
59192
|
+
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59193
|
+
follow: false
|
|
59194
|
+
});
|
|
59195
|
+
}
|
|
59196
|
+
}
|
|
59197
|
+
return {
|
|
59198
|
+
reverse_config,
|
|
59199
|
+
reverse_action,
|
|
59200
|
+
reverse_orders_to_buy,
|
|
59201
|
+
positions: {
|
|
59202
|
+
long: long_position,
|
|
59203
|
+
short: short_position
|
|
59204
|
+
},
|
|
59205
|
+
orders_to_place,
|
|
59206
|
+
config_details: {
|
|
59207
|
+
app_config,
|
|
59208
|
+
last_value,
|
|
59209
|
+
config: config2,
|
|
59210
|
+
pnl
|
|
59211
|
+
}
|
|
59212
|
+
};
|
|
59213
|
+
}
|
|
59072
59214
|
}
|
|
59073
59215
|
async function initApp(payload) {
|
|
59074
59216
|
const pb = await initPocketBaseClient(payload.db);
|
package/dist/index.d.ts
CHANGED
|
@@ -1737,16 +1737,6 @@ declare class App {
|
|
|
1737
1737
|
message?: undefined;
|
|
1738
1738
|
exchange_result?: undefined;
|
|
1739
1739
|
}>;
|
|
1740
|
-
updateReduceRatio(payload: {
|
|
1741
|
-
account: ExchangeType;
|
|
1742
|
-
symbol: string;
|
|
1743
|
-
}): Promise<{
|
|
1744
|
-
long_position: any;
|
|
1745
|
-
short_position: any;
|
|
1746
|
-
long_db_position: any;
|
|
1747
|
-
short_db_position: any;
|
|
1748
|
-
balance: any;
|
|
1749
|
-
}>;
|
|
1750
1740
|
getWindingDownMarkets(): Promise<WindingDownMarket[]>;
|
|
1751
1741
|
updateSymbolConfigs(payload: {
|
|
1752
1742
|
configs: {
|
|
@@ -1793,6 +1783,102 @@ declare class App {
|
|
|
1793
1783
|
cancel?: boolean;
|
|
1794
1784
|
raw?: boolean;
|
|
1795
1785
|
}): Promise<any>;
|
|
1786
|
+
profitWithinGapStrategy(payload: {
|
|
1787
|
+
account: ExchangeType;
|
|
1788
|
+
symbol: string;
|
|
1789
|
+
kind: "long" | "short";
|
|
1790
|
+
risk: number;
|
|
1791
|
+
resistance: number;
|
|
1792
|
+
support: number;
|
|
1793
|
+
reward_factor?: number;
|
|
1794
|
+
}): Promise<{
|
|
1795
|
+
reverse_config: any;
|
|
1796
|
+
reverse_action: {
|
|
1797
|
+
avg: {
|
|
1798
|
+
entry: number;
|
|
1799
|
+
price: number;
|
|
1800
|
+
quantity: number;
|
|
1801
|
+
};
|
|
1802
|
+
loss: number;
|
|
1803
|
+
profit_percent: number;
|
|
1804
|
+
fee: number;
|
|
1805
|
+
risk_per_trade: number;
|
|
1806
|
+
risk_reward: number;
|
|
1807
|
+
symbol?: string;
|
|
1808
|
+
focus: number;
|
|
1809
|
+
budget: number;
|
|
1810
|
+
support: number;
|
|
1811
|
+
resistance: number;
|
|
1812
|
+
percent_change: number;
|
|
1813
|
+
tradeSplit?: number;
|
|
1814
|
+
take_profit?: number;
|
|
1815
|
+
kind: "long" | "short";
|
|
1816
|
+
entry: number;
|
|
1817
|
+
stop: number;
|
|
1818
|
+
min_size: number;
|
|
1819
|
+
price_places?: string;
|
|
1820
|
+
strategy?: "quantity" | "entry";
|
|
1821
|
+
as_array?: boolean;
|
|
1822
|
+
decimal_places?: string;
|
|
1823
|
+
min_profit?: number;
|
|
1824
|
+
raw?: boolean;
|
|
1825
|
+
gap?: number;
|
|
1826
|
+
rr?: number;
|
|
1827
|
+
max_size?: number;
|
|
1828
|
+
};
|
|
1829
|
+
reverse_orders_to_buy: any;
|
|
1830
|
+
positions: {
|
|
1831
|
+
long: PositionsView;
|
|
1832
|
+
short: PositionsView;
|
|
1833
|
+
};
|
|
1834
|
+
orders_to_place: any;
|
|
1835
|
+
config_details: {
|
|
1836
|
+
app_config: {
|
|
1837
|
+
fee: number;
|
|
1838
|
+
risk_per_trade: number;
|
|
1839
|
+
risk_reward: number;
|
|
1840
|
+
symbol?: string;
|
|
1841
|
+
focus: number;
|
|
1842
|
+
budget: number;
|
|
1843
|
+
support: number;
|
|
1844
|
+
resistance: number;
|
|
1845
|
+
percent_change: number;
|
|
1846
|
+
tradeSplit?: number;
|
|
1847
|
+
take_profit?: number;
|
|
1848
|
+
kind: "long" | "short";
|
|
1849
|
+
entry: number;
|
|
1850
|
+
stop: number;
|
|
1851
|
+
min_size: number;
|
|
1852
|
+
price_places?: string;
|
|
1853
|
+
strategy?: "quantity" | "entry";
|
|
1854
|
+
as_array?: boolean;
|
|
1855
|
+
decimal_places?: string;
|
|
1856
|
+
min_profit?: number;
|
|
1857
|
+
raw?: boolean;
|
|
1858
|
+
gap?: number;
|
|
1859
|
+
rr?: number;
|
|
1860
|
+
max_size?: number;
|
|
1861
|
+
};
|
|
1862
|
+
last_value: any;
|
|
1863
|
+
config: {
|
|
1864
|
+
entry: number;
|
|
1865
|
+
stop: number;
|
|
1866
|
+
risk: number;
|
|
1867
|
+
risk_reward: number | {
|
|
1868
|
+
result: any[];
|
|
1869
|
+
value: number;
|
|
1870
|
+
total: number;
|
|
1871
|
+
risk_per_trade: number;
|
|
1872
|
+
max: number;
|
|
1873
|
+
min: number;
|
|
1874
|
+
neg_pnl: any;
|
|
1875
|
+
entry: any;
|
|
1876
|
+
};
|
|
1877
|
+
profit_percent: number;
|
|
1878
|
+
};
|
|
1879
|
+
pnl: number;
|
|
1880
|
+
};
|
|
1881
|
+
}>;
|
|
1796
1882
|
}
|
|
1797
1883
|
export declare function initApp(payload: {
|
|
1798
1884
|
db: {
|
package/dist/index.js
CHANGED
|
@@ -53069,7 +53069,7 @@ class Signal {
|
|
|
53069
53069
|
new_stop
|
|
53070
53070
|
};
|
|
53071
53071
|
});
|
|
53072
|
-
if (greater_than_min_size.length !==
|
|
53072
|
+
if (greater_than_min_size.length !== total_orders.length) {
|
|
53073
53073
|
payload = greater_than_min_size.concat(less_than_min_size);
|
|
53074
53074
|
}
|
|
53075
53075
|
return payload;
|
|
@@ -58725,7 +58725,6 @@ async function getExchangeAccount(payload) {
|
|
|
58725
58725
|
app_db
|
|
58726
58726
|
});
|
|
58727
58727
|
}
|
|
58728
|
-
|
|
58729
58728
|
// src/app.ts
|
|
58730
58729
|
class App {
|
|
58731
58730
|
app_db;
|
|
@@ -58784,37 +58783,6 @@ class App {
|
|
|
58784
58783
|
stop: payload.stop
|
|
58785
58784
|
});
|
|
58786
58785
|
}
|
|
58787
|
-
async updateReduceRatio(payload) {
|
|
58788
|
-
const { symbol } = payload;
|
|
58789
|
-
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
58790
|
-
const positions = await exchange_account.syncAccount({
|
|
58791
|
-
as_view: true,
|
|
58792
|
-
symbol
|
|
58793
|
-
});
|
|
58794
|
-
const active_account = await exchange_account.getActiveAccount({
|
|
58795
|
-
symbol
|
|
58796
|
-
});
|
|
58797
|
-
const long_position = active_account.position.long;
|
|
58798
|
-
const short_position = active_account.position.short;
|
|
58799
|
-
const long_db_position = positions.find((p) => p.kind === "long");
|
|
58800
|
-
const short_db_position = positions.find((p) => p.kind === "short");
|
|
58801
|
-
const balance = active_account.usd_balance || 0;
|
|
58802
|
-
const long_liquidation = long_db_position.avg_price * long_db_position.avg_qty / long_db_position.leverage - balance / long_db_position.avg_qty + long_db_position.avg_price;
|
|
58803
|
-
const short_liquidation = -(short_db_position.avg_price * short_db_position.avg_qty / short_db_position.leverage) + balance / short_db_position.avg_qty + short_db_position.avg_price;
|
|
58804
|
-
long_position.avg_liquidation = to_f2(long_liquidation, "%.3f");
|
|
58805
|
-
short_position.avg_liquidation = to_f2(short_liquidation, "%.3f");
|
|
58806
|
-
const long_ratio = Math.max(long_position.avg_liquidation, long_position.avg_entry) / Math.min(long_position.avg_liquidation, long_position.avg_entry) - 1;
|
|
58807
|
-
const short_ratio = Math.max(short_position.avg_liquidation, short_position.avg_entry) / Math.min(short_position.avg_liquidation, short_position.avg_entry) - 1;
|
|
58808
|
-
long_position.liquidation_ratio = to_f2(long_ratio, "%.3f") * 100;
|
|
58809
|
-
short_position.liquidation_ratio = to_f2(short_ratio, "%.3f") * 100;
|
|
58810
|
-
return {
|
|
58811
|
-
long_position,
|
|
58812
|
-
short_position,
|
|
58813
|
-
long_db_position,
|
|
58814
|
-
short_db_position,
|
|
58815
|
-
balance: active_account.usd_balance
|
|
58816
|
-
};
|
|
58817
|
-
}
|
|
58818
58786
|
async getWindingDownMarkets() {
|
|
58819
58787
|
return await this.app_db.getWindingDownMarkets();
|
|
58820
58788
|
}
|
|
@@ -59024,6 +58992,180 @@ class App {
|
|
|
59024
58992
|
});
|
|
59025
58993
|
return result;
|
|
59026
58994
|
}
|
|
58995
|
+
async profitWithinGapStrategy(payload) {
|
|
58996
|
+
const {
|
|
58997
|
+
account,
|
|
58998
|
+
symbol,
|
|
58999
|
+
kind,
|
|
59000
|
+
risk,
|
|
59001
|
+
resistance,
|
|
59002
|
+
support,
|
|
59003
|
+
reward_factor = 1
|
|
59004
|
+
} = payload;
|
|
59005
|
+
const exchange_account = await this.getExchangeAccount(account);
|
|
59006
|
+
console.log("Getting entry and stop for ", symbol, kind);
|
|
59007
|
+
const entry = kind === "long" ? resistance : support;
|
|
59008
|
+
const stop = kind === "long" ? support : resistance;
|
|
59009
|
+
console.log("Building app config for ", symbol, kind);
|
|
59010
|
+
const initial_app_config = await exchange_account.buildAppConfig({
|
|
59011
|
+
entry,
|
|
59012
|
+
stop,
|
|
59013
|
+
risk_reward: 199,
|
|
59014
|
+
risk,
|
|
59015
|
+
symbol
|
|
59016
|
+
});
|
|
59017
|
+
console.log("Computing risk reward for ", symbol, kind);
|
|
59018
|
+
const risk_reward = computeRiskReward({
|
|
59019
|
+
app_config: initial_app_config,
|
|
59020
|
+
entry: initial_app_config.entry,
|
|
59021
|
+
stop: initial_app_config.stop,
|
|
59022
|
+
risk_per_trade: initial_app_config.risk_per_trade
|
|
59023
|
+
});
|
|
59024
|
+
console.log("Re-computing app config for ", symbol, kind);
|
|
59025
|
+
const { entries, last_value, ...app_config } = await exchange_account.buildAppConfig({
|
|
59026
|
+
entry: initial_app_config.entry,
|
|
59027
|
+
stop: initial_app_config.stop,
|
|
59028
|
+
risk_reward,
|
|
59029
|
+
risk,
|
|
59030
|
+
symbol
|
|
59031
|
+
});
|
|
59032
|
+
console.log("Computing profit percent for ", symbol, kind);
|
|
59033
|
+
const pnl = reward_factor * risk;
|
|
59034
|
+
const profit_percent = to_f2(pnl * 100 / (last_value.avg_entry * last_value.avg_size), "%.4f");
|
|
59035
|
+
let config2 = {
|
|
59036
|
+
entry,
|
|
59037
|
+
stop,
|
|
59038
|
+
risk,
|
|
59039
|
+
risk_reward,
|
|
59040
|
+
profit_percent
|
|
59041
|
+
};
|
|
59042
|
+
console.log("Saving new config for ", symbol, kind);
|
|
59043
|
+
const data = await exchange_account.getPositionConfig({
|
|
59044
|
+
symbol,
|
|
59045
|
+
kind,
|
|
59046
|
+
params: config2
|
|
59047
|
+
});
|
|
59048
|
+
console.log("Checking orders to place for ", symbol, kind);
|
|
59049
|
+
const orders_to_place = await exchange_account.placeTrade({
|
|
59050
|
+
symbol,
|
|
59051
|
+
raw: true,
|
|
59052
|
+
kind,
|
|
59053
|
+
place: false
|
|
59054
|
+
});
|
|
59055
|
+
config2 = {
|
|
59056
|
+
...config2,
|
|
59057
|
+
...data
|
|
59058
|
+
};
|
|
59059
|
+
console.log("Fetching positions for ", symbol);
|
|
59060
|
+
const positions = await exchange_account.syncAccount({
|
|
59061
|
+
symbol,
|
|
59062
|
+
as_view: true
|
|
59063
|
+
});
|
|
59064
|
+
console.log("Getting long and short positions for ", symbol);
|
|
59065
|
+
const long_position = positions.find((k) => k.kind === "long");
|
|
59066
|
+
const short_position = positions.find((k) => k.kind === "short");
|
|
59067
|
+
console.log("Getting focus position for ", symbol, kind);
|
|
59068
|
+
const focus_position = kind === "long" ? long_position : short_position;
|
|
59069
|
+
const reverse_position = kind === "long" ? short_position : long_position;
|
|
59070
|
+
let reverse_action = null;
|
|
59071
|
+
let reverse_orders_to_buy = [];
|
|
59072
|
+
let reverse_config = null;
|
|
59073
|
+
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
59074
|
+
if (focus_position.quantity > 0) {
|
|
59075
|
+
console.log("Getting details for ", reverse_position.kind);
|
|
59076
|
+
reverse_action = await exchange_account.buildOppositeTrades({
|
|
59077
|
+
symbol,
|
|
59078
|
+
kind
|
|
59079
|
+
});
|
|
59080
|
+
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
59081
|
+
await exchange_account.getPositionConfig({
|
|
59082
|
+
symbol,
|
|
59083
|
+
kind: reverse_action.kind,
|
|
59084
|
+
params: {
|
|
59085
|
+
entry: reverse_action.entry,
|
|
59086
|
+
stop: reverse_action.stop,
|
|
59087
|
+
risk: reverse_action.risk_per_trade,
|
|
59088
|
+
profit_percent: reverse_action.profit_percent,
|
|
59089
|
+
risk_reward: reverse_action.risk_reward
|
|
59090
|
+
}
|
|
59091
|
+
});
|
|
59092
|
+
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
59093
|
+
const reverse_app_config = await exchange_account.buildAppConfig({
|
|
59094
|
+
entry: reverse_action.entry,
|
|
59095
|
+
stop: reverse_action.stop,
|
|
59096
|
+
risk_reward: reverse_action.risk_reward,
|
|
59097
|
+
risk: reverse_action.risk_per_trade,
|
|
59098
|
+
symbol
|
|
59099
|
+
});
|
|
59100
|
+
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
59101
|
+
reverse_orders_to_buy = await exchange_account.placeTrade({
|
|
59102
|
+
symbol,
|
|
59103
|
+
raw: true,
|
|
59104
|
+
kind: reverse_action.kind,
|
|
59105
|
+
place: false
|
|
59106
|
+
});
|
|
59107
|
+
let _reverse_config = {
|
|
59108
|
+
avg: reverse_action.avg,
|
|
59109
|
+
entry: reverse_action.entry,
|
|
59110
|
+
stop: reverse_action.stop,
|
|
59111
|
+
risk_per_trade: reverse_action.risk_per_trade,
|
|
59112
|
+
profit_percent: reverse_action.profit_percent,
|
|
59113
|
+
risk_reward: reverse_action.risk_reward
|
|
59114
|
+
};
|
|
59115
|
+
if (reverse_orders_to_buy.length > 0) {
|
|
59116
|
+
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
59117
|
+
let existing = await exchange_account.placeOppositeTradeAction({
|
|
59118
|
+
symbol,
|
|
59119
|
+
kind: reverse_action.kind,
|
|
59120
|
+
data: _reverse_config
|
|
59121
|
+
});
|
|
59122
|
+
_reverse_config = {
|
|
59123
|
+
...existing,
|
|
59124
|
+
..._reverse_config
|
|
59125
|
+
};
|
|
59126
|
+
}
|
|
59127
|
+
reverse_config = _reverse_config;
|
|
59128
|
+
}
|
|
59129
|
+
if (!reverse_config?.id) {
|
|
59130
|
+
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
59131
|
+
reverse_config = await exchange_account.getPositionConfig({
|
|
59132
|
+
symbol,
|
|
59133
|
+
kind: reverse_action.kind
|
|
59134
|
+
});
|
|
59135
|
+
}
|
|
59136
|
+
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
59137
|
+
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
59138
|
+
const max_size = app_config.max_size * 0.98;
|
|
59139
|
+
if (reverse_config.threshold_qty !== max_size) {
|
|
59140
|
+
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59141
|
+
follow: true,
|
|
59142
|
+
threshold_qty: max_size
|
|
59143
|
+
});
|
|
59144
|
+
}
|
|
59145
|
+
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
59146
|
+
} else {
|
|
59147
|
+
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59148
|
+
follow: false
|
|
59149
|
+
});
|
|
59150
|
+
}
|
|
59151
|
+
}
|
|
59152
|
+
return {
|
|
59153
|
+
reverse_config,
|
|
59154
|
+
reverse_action,
|
|
59155
|
+
reverse_orders_to_buy,
|
|
59156
|
+
positions: {
|
|
59157
|
+
long: long_position,
|
|
59158
|
+
short: short_position
|
|
59159
|
+
},
|
|
59160
|
+
orders_to_place,
|
|
59161
|
+
config_details: {
|
|
59162
|
+
app_config,
|
|
59163
|
+
last_value,
|
|
59164
|
+
config: config2,
|
|
59165
|
+
pnl
|
|
59166
|
+
}
|
|
59167
|
+
};
|
|
59168
|
+
}
|
|
59027
59169
|
}
|
|
59028
59170
|
async function initApp(payload) {
|
|
59029
59171
|
const pb = await initPocketBaseClient(payload.db);
|
package/dist/mcp-server.cjs
CHANGED
|
@@ -59818,7 +59818,7 @@ class Signal {
|
|
|
59818
59818
|
new_stop
|
|
59819
59819
|
};
|
|
59820
59820
|
});
|
|
59821
|
-
if (greater_than_min_size.length !==
|
|
59821
|
+
if (greater_than_min_size.length !== total_orders.length) {
|
|
59822
59822
|
payload = greater_than_min_size.concat(less_than_min_size);
|
|
59823
59823
|
}
|
|
59824
59824
|
return payload;
|
|
@@ -65461,7 +65461,6 @@ async function getExchangeAccount(payload) {
|
|
|
65461
65461
|
app_db
|
|
65462
65462
|
});
|
|
65463
65463
|
}
|
|
65464
|
-
|
|
65465
65464
|
// src/app.ts
|
|
65466
65465
|
class App {
|
|
65467
65466
|
app_db;
|
|
@@ -65520,37 +65519,6 @@ class App {
|
|
|
65520
65519
|
stop: payload.stop
|
|
65521
65520
|
});
|
|
65522
65521
|
}
|
|
65523
|
-
async updateReduceRatio(payload) {
|
|
65524
|
-
const { symbol } = payload;
|
|
65525
|
-
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
65526
|
-
const positions = await exchange_account.syncAccount({
|
|
65527
|
-
as_view: true,
|
|
65528
|
-
symbol
|
|
65529
|
-
});
|
|
65530
|
-
const active_account = await exchange_account.getActiveAccount({
|
|
65531
|
-
symbol
|
|
65532
|
-
});
|
|
65533
|
-
const long_position = active_account.position.long;
|
|
65534
|
-
const short_position = active_account.position.short;
|
|
65535
|
-
const long_db_position = positions.find((p) => p.kind === "long");
|
|
65536
|
-
const short_db_position = positions.find((p) => p.kind === "short");
|
|
65537
|
-
const balance = active_account.usd_balance || 0;
|
|
65538
|
-
const long_liquidation = long_db_position.avg_price * long_db_position.avg_qty / long_db_position.leverage - balance / long_db_position.avg_qty + long_db_position.avg_price;
|
|
65539
|
-
const short_liquidation = -(short_db_position.avg_price * short_db_position.avg_qty / short_db_position.leverage) + balance / short_db_position.avg_qty + short_db_position.avg_price;
|
|
65540
|
-
long_position.avg_liquidation = to_f2(long_liquidation, "%.3f");
|
|
65541
|
-
short_position.avg_liquidation = to_f2(short_liquidation, "%.3f");
|
|
65542
|
-
const long_ratio = Math.max(long_position.avg_liquidation, long_position.avg_entry) / Math.min(long_position.avg_liquidation, long_position.avg_entry) - 1;
|
|
65543
|
-
const short_ratio = Math.max(short_position.avg_liquidation, short_position.avg_entry) / Math.min(short_position.avg_liquidation, short_position.avg_entry) - 1;
|
|
65544
|
-
long_position.liquidation_ratio = to_f2(long_ratio, "%.3f") * 100;
|
|
65545
|
-
short_position.liquidation_ratio = to_f2(short_ratio, "%.3f") * 100;
|
|
65546
|
-
return {
|
|
65547
|
-
long_position,
|
|
65548
|
-
short_position,
|
|
65549
|
-
long_db_position,
|
|
65550
|
-
short_db_position,
|
|
65551
|
-
balance: active_account.usd_balance
|
|
65552
|
-
};
|
|
65553
|
-
}
|
|
65554
65522
|
async getWindingDownMarkets() {
|
|
65555
65523
|
return await this.app_db.getWindingDownMarkets();
|
|
65556
65524
|
}
|
|
@@ -65760,6 +65728,180 @@ class App {
|
|
|
65760
65728
|
});
|
|
65761
65729
|
return result;
|
|
65762
65730
|
}
|
|
65731
|
+
async profitWithinGapStrategy(payload) {
|
|
65732
|
+
const {
|
|
65733
|
+
account,
|
|
65734
|
+
symbol,
|
|
65735
|
+
kind,
|
|
65736
|
+
risk,
|
|
65737
|
+
resistance,
|
|
65738
|
+
support,
|
|
65739
|
+
reward_factor = 1
|
|
65740
|
+
} = payload;
|
|
65741
|
+
const exchange_account = await this.getExchangeAccount(account);
|
|
65742
|
+
console.log("Getting entry and stop for ", symbol, kind);
|
|
65743
|
+
const entry = kind === "long" ? resistance : support;
|
|
65744
|
+
const stop = kind === "long" ? support : resistance;
|
|
65745
|
+
console.log("Building app config for ", symbol, kind);
|
|
65746
|
+
const initial_app_config = await exchange_account.buildAppConfig({
|
|
65747
|
+
entry,
|
|
65748
|
+
stop,
|
|
65749
|
+
risk_reward: 199,
|
|
65750
|
+
risk,
|
|
65751
|
+
symbol
|
|
65752
|
+
});
|
|
65753
|
+
console.log("Computing risk reward for ", symbol, kind);
|
|
65754
|
+
const risk_reward = computeRiskReward({
|
|
65755
|
+
app_config: initial_app_config,
|
|
65756
|
+
entry: initial_app_config.entry,
|
|
65757
|
+
stop: initial_app_config.stop,
|
|
65758
|
+
risk_per_trade: initial_app_config.risk_per_trade
|
|
65759
|
+
});
|
|
65760
|
+
console.log("Re-computing app config for ", symbol, kind);
|
|
65761
|
+
const { entries, last_value, ...app_config } = await exchange_account.buildAppConfig({
|
|
65762
|
+
entry: initial_app_config.entry,
|
|
65763
|
+
stop: initial_app_config.stop,
|
|
65764
|
+
risk_reward,
|
|
65765
|
+
risk,
|
|
65766
|
+
symbol
|
|
65767
|
+
});
|
|
65768
|
+
console.log("Computing profit percent for ", symbol, kind);
|
|
65769
|
+
const pnl = reward_factor * risk;
|
|
65770
|
+
const profit_percent = to_f2(pnl * 100 / (last_value.avg_entry * last_value.avg_size), "%.4f");
|
|
65771
|
+
let config2 = {
|
|
65772
|
+
entry,
|
|
65773
|
+
stop,
|
|
65774
|
+
risk,
|
|
65775
|
+
risk_reward,
|
|
65776
|
+
profit_percent
|
|
65777
|
+
};
|
|
65778
|
+
console.log("Saving new config for ", symbol, kind);
|
|
65779
|
+
const data = await exchange_account.getPositionConfig({
|
|
65780
|
+
symbol,
|
|
65781
|
+
kind,
|
|
65782
|
+
params: config2
|
|
65783
|
+
});
|
|
65784
|
+
console.log("Checking orders to place for ", symbol, kind);
|
|
65785
|
+
const orders_to_place = await exchange_account.placeTrade({
|
|
65786
|
+
symbol,
|
|
65787
|
+
raw: true,
|
|
65788
|
+
kind,
|
|
65789
|
+
place: false
|
|
65790
|
+
});
|
|
65791
|
+
config2 = {
|
|
65792
|
+
...config2,
|
|
65793
|
+
...data
|
|
65794
|
+
};
|
|
65795
|
+
console.log("Fetching positions for ", symbol);
|
|
65796
|
+
const positions = await exchange_account.syncAccount({
|
|
65797
|
+
symbol,
|
|
65798
|
+
as_view: true
|
|
65799
|
+
});
|
|
65800
|
+
console.log("Getting long and short positions for ", symbol);
|
|
65801
|
+
const long_position = positions.find((k) => k.kind === "long");
|
|
65802
|
+
const short_position = positions.find((k) => k.kind === "short");
|
|
65803
|
+
console.log("Getting focus position for ", symbol, kind);
|
|
65804
|
+
const focus_position = kind === "long" ? long_position : short_position;
|
|
65805
|
+
const reverse_position = kind === "long" ? short_position : long_position;
|
|
65806
|
+
let reverse_action = null;
|
|
65807
|
+
let reverse_orders_to_buy = [];
|
|
65808
|
+
let reverse_config = null;
|
|
65809
|
+
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
65810
|
+
if (focus_position.quantity > 0) {
|
|
65811
|
+
console.log("Getting details for ", reverse_position.kind);
|
|
65812
|
+
reverse_action = await exchange_account.buildOppositeTrades({
|
|
65813
|
+
symbol,
|
|
65814
|
+
kind
|
|
65815
|
+
});
|
|
65816
|
+
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
65817
|
+
await exchange_account.getPositionConfig({
|
|
65818
|
+
symbol,
|
|
65819
|
+
kind: reverse_action.kind,
|
|
65820
|
+
params: {
|
|
65821
|
+
entry: reverse_action.entry,
|
|
65822
|
+
stop: reverse_action.stop,
|
|
65823
|
+
risk: reverse_action.risk_per_trade,
|
|
65824
|
+
profit_percent: reverse_action.profit_percent,
|
|
65825
|
+
risk_reward: reverse_action.risk_reward
|
|
65826
|
+
}
|
|
65827
|
+
});
|
|
65828
|
+
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
65829
|
+
const reverse_app_config = await exchange_account.buildAppConfig({
|
|
65830
|
+
entry: reverse_action.entry,
|
|
65831
|
+
stop: reverse_action.stop,
|
|
65832
|
+
risk_reward: reverse_action.risk_reward,
|
|
65833
|
+
risk: reverse_action.risk_per_trade,
|
|
65834
|
+
symbol
|
|
65835
|
+
});
|
|
65836
|
+
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
65837
|
+
reverse_orders_to_buy = await exchange_account.placeTrade({
|
|
65838
|
+
symbol,
|
|
65839
|
+
raw: true,
|
|
65840
|
+
kind: reverse_action.kind,
|
|
65841
|
+
place: false
|
|
65842
|
+
});
|
|
65843
|
+
let _reverse_config = {
|
|
65844
|
+
avg: reverse_action.avg,
|
|
65845
|
+
entry: reverse_action.entry,
|
|
65846
|
+
stop: reverse_action.stop,
|
|
65847
|
+
risk_per_trade: reverse_action.risk_per_trade,
|
|
65848
|
+
profit_percent: reverse_action.profit_percent,
|
|
65849
|
+
risk_reward: reverse_action.risk_reward
|
|
65850
|
+
};
|
|
65851
|
+
if (reverse_orders_to_buy.length > 0) {
|
|
65852
|
+
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
65853
|
+
let existing = await exchange_account.placeOppositeTradeAction({
|
|
65854
|
+
symbol,
|
|
65855
|
+
kind: reverse_action.kind,
|
|
65856
|
+
data: _reverse_config
|
|
65857
|
+
});
|
|
65858
|
+
_reverse_config = {
|
|
65859
|
+
...existing,
|
|
65860
|
+
..._reverse_config
|
|
65861
|
+
};
|
|
65862
|
+
}
|
|
65863
|
+
reverse_config = _reverse_config;
|
|
65864
|
+
}
|
|
65865
|
+
if (!reverse_config?.id) {
|
|
65866
|
+
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
65867
|
+
reverse_config = await exchange_account.getPositionConfig({
|
|
65868
|
+
symbol,
|
|
65869
|
+
kind: reverse_action.kind
|
|
65870
|
+
});
|
|
65871
|
+
}
|
|
65872
|
+
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
65873
|
+
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
65874
|
+
const max_size = app_config.max_size * 0.98;
|
|
65875
|
+
if (reverse_config.threshold_qty !== max_size) {
|
|
65876
|
+
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
65877
|
+
follow: true,
|
|
65878
|
+
threshold_qty: max_size
|
|
65879
|
+
});
|
|
65880
|
+
}
|
|
65881
|
+
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
65882
|
+
} else {
|
|
65883
|
+
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
65884
|
+
follow: false
|
|
65885
|
+
});
|
|
65886
|
+
}
|
|
65887
|
+
}
|
|
65888
|
+
return {
|
|
65889
|
+
reverse_config,
|
|
65890
|
+
reverse_action,
|
|
65891
|
+
reverse_orders_to_buy,
|
|
65892
|
+
positions: {
|
|
65893
|
+
long: long_position,
|
|
65894
|
+
short: short_position
|
|
65895
|
+
},
|
|
65896
|
+
orders_to_place,
|
|
65897
|
+
config_details: {
|
|
65898
|
+
app_config,
|
|
65899
|
+
last_value,
|
|
65900
|
+
config: config2,
|
|
65901
|
+
pnl
|
|
65902
|
+
}
|
|
65903
|
+
};
|
|
65904
|
+
}
|
|
65763
65905
|
}
|
|
65764
65906
|
async function initApp(payload) {
|
|
65765
65907
|
const pb = await initPocketBaseClient(payload.db);
|
|
@@ -65894,13 +66036,13 @@ async function getPositions(payload) {
|
|
|
65894
66036
|
const symbol_config = await exchange_account.recomputeSymbolConfig({
|
|
65895
66037
|
symbol: payload.symbol
|
|
65896
66038
|
});
|
|
65897
|
-
const
|
|
66039
|
+
const strategy2 = await exchange_account.getPositionStrategy();
|
|
65898
66040
|
const strategy_config = {
|
|
65899
|
-
tp_percent:
|
|
65900
|
-
short_tp_factor:
|
|
65901
|
-
fee_percent:
|
|
65902
|
-
budget:
|
|
65903
|
-
risk_reward:
|
|
66041
|
+
tp_percent: strategy2?.tp_percent,
|
|
66042
|
+
short_tp_factor: strategy2?.short_tp_factor,
|
|
66043
|
+
fee_percent: strategy2?.fee_percent,
|
|
66044
|
+
budget: strategy2?.budget,
|
|
66045
|
+
risk_reward: strategy2?.risk_reward,
|
|
65904
66046
|
global_config: symbol_config
|
|
65905
66047
|
};
|
|
65906
66048
|
const positions = await exchange_account.syncAccount({
|
package/dist/mcp-server.js
CHANGED
|
@@ -59795,7 +59795,7 @@ class Signal {
|
|
|
59795
59795
|
new_stop
|
|
59796
59796
|
};
|
|
59797
59797
|
});
|
|
59798
|
-
if (greater_than_min_size.length !==
|
|
59798
|
+
if (greater_than_min_size.length !== total_orders.length) {
|
|
59799
59799
|
payload = greater_than_min_size.concat(less_than_min_size);
|
|
59800
59800
|
}
|
|
59801
59801
|
return payload;
|
|
@@ -65438,7 +65438,6 @@ async function getExchangeAccount(payload) {
|
|
|
65438
65438
|
app_db
|
|
65439
65439
|
});
|
|
65440
65440
|
}
|
|
65441
|
-
|
|
65442
65441
|
// src/app.ts
|
|
65443
65442
|
class App {
|
|
65444
65443
|
app_db;
|
|
@@ -65497,37 +65496,6 @@ class App {
|
|
|
65497
65496
|
stop: payload.stop
|
|
65498
65497
|
});
|
|
65499
65498
|
}
|
|
65500
|
-
async updateReduceRatio(payload) {
|
|
65501
|
-
const { symbol } = payload;
|
|
65502
|
-
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
65503
|
-
const positions = await exchange_account.syncAccount({
|
|
65504
|
-
as_view: true,
|
|
65505
|
-
symbol
|
|
65506
|
-
});
|
|
65507
|
-
const active_account = await exchange_account.getActiveAccount({
|
|
65508
|
-
symbol
|
|
65509
|
-
});
|
|
65510
|
-
const long_position = active_account.position.long;
|
|
65511
|
-
const short_position = active_account.position.short;
|
|
65512
|
-
const long_db_position = positions.find((p) => p.kind === "long");
|
|
65513
|
-
const short_db_position = positions.find((p) => p.kind === "short");
|
|
65514
|
-
const balance = active_account.usd_balance || 0;
|
|
65515
|
-
const long_liquidation = long_db_position.avg_price * long_db_position.avg_qty / long_db_position.leverage - balance / long_db_position.avg_qty + long_db_position.avg_price;
|
|
65516
|
-
const short_liquidation = -(short_db_position.avg_price * short_db_position.avg_qty / short_db_position.leverage) + balance / short_db_position.avg_qty + short_db_position.avg_price;
|
|
65517
|
-
long_position.avg_liquidation = to_f2(long_liquidation, "%.3f");
|
|
65518
|
-
short_position.avg_liquidation = to_f2(short_liquidation, "%.3f");
|
|
65519
|
-
const long_ratio = Math.max(long_position.avg_liquidation, long_position.avg_entry) / Math.min(long_position.avg_liquidation, long_position.avg_entry) - 1;
|
|
65520
|
-
const short_ratio = Math.max(short_position.avg_liquidation, short_position.avg_entry) / Math.min(short_position.avg_liquidation, short_position.avg_entry) - 1;
|
|
65521
|
-
long_position.liquidation_ratio = to_f2(long_ratio, "%.3f") * 100;
|
|
65522
|
-
short_position.liquidation_ratio = to_f2(short_ratio, "%.3f") * 100;
|
|
65523
|
-
return {
|
|
65524
|
-
long_position,
|
|
65525
|
-
short_position,
|
|
65526
|
-
long_db_position,
|
|
65527
|
-
short_db_position,
|
|
65528
|
-
balance: active_account.usd_balance
|
|
65529
|
-
};
|
|
65530
|
-
}
|
|
65531
65499
|
async getWindingDownMarkets() {
|
|
65532
65500
|
return await this.app_db.getWindingDownMarkets();
|
|
65533
65501
|
}
|
|
@@ -65737,6 +65705,180 @@ class App {
|
|
|
65737
65705
|
});
|
|
65738
65706
|
return result;
|
|
65739
65707
|
}
|
|
65708
|
+
async profitWithinGapStrategy(payload) {
|
|
65709
|
+
const {
|
|
65710
|
+
account,
|
|
65711
|
+
symbol,
|
|
65712
|
+
kind,
|
|
65713
|
+
risk,
|
|
65714
|
+
resistance,
|
|
65715
|
+
support,
|
|
65716
|
+
reward_factor = 1
|
|
65717
|
+
} = payload;
|
|
65718
|
+
const exchange_account = await this.getExchangeAccount(account);
|
|
65719
|
+
console.log("Getting entry and stop for ", symbol, kind);
|
|
65720
|
+
const entry = kind === "long" ? resistance : support;
|
|
65721
|
+
const stop = kind === "long" ? support : resistance;
|
|
65722
|
+
console.log("Building app config for ", symbol, kind);
|
|
65723
|
+
const initial_app_config = await exchange_account.buildAppConfig({
|
|
65724
|
+
entry,
|
|
65725
|
+
stop,
|
|
65726
|
+
risk_reward: 199,
|
|
65727
|
+
risk,
|
|
65728
|
+
symbol
|
|
65729
|
+
});
|
|
65730
|
+
console.log("Computing risk reward for ", symbol, kind);
|
|
65731
|
+
const risk_reward = computeRiskReward({
|
|
65732
|
+
app_config: initial_app_config,
|
|
65733
|
+
entry: initial_app_config.entry,
|
|
65734
|
+
stop: initial_app_config.stop,
|
|
65735
|
+
risk_per_trade: initial_app_config.risk_per_trade
|
|
65736
|
+
});
|
|
65737
|
+
console.log("Re-computing app config for ", symbol, kind);
|
|
65738
|
+
const { entries, last_value, ...app_config } = await exchange_account.buildAppConfig({
|
|
65739
|
+
entry: initial_app_config.entry,
|
|
65740
|
+
stop: initial_app_config.stop,
|
|
65741
|
+
risk_reward,
|
|
65742
|
+
risk,
|
|
65743
|
+
symbol
|
|
65744
|
+
});
|
|
65745
|
+
console.log("Computing profit percent for ", symbol, kind);
|
|
65746
|
+
const pnl = reward_factor * risk;
|
|
65747
|
+
const profit_percent = to_f2(pnl * 100 / (last_value.avg_entry * last_value.avg_size), "%.4f");
|
|
65748
|
+
let config2 = {
|
|
65749
|
+
entry,
|
|
65750
|
+
stop,
|
|
65751
|
+
risk,
|
|
65752
|
+
risk_reward,
|
|
65753
|
+
profit_percent
|
|
65754
|
+
};
|
|
65755
|
+
console.log("Saving new config for ", symbol, kind);
|
|
65756
|
+
const data = await exchange_account.getPositionConfig({
|
|
65757
|
+
symbol,
|
|
65758
|
+
kind,
|
|
65759
|
+
params: config2
|
|
65760
|
+
});
|
|
65761
|
+
console.log("Checking orders to place for ", symbol, kind);
|
|
65762
|
+
const orders_to_place = await exchange_account.placeTrade({
|
|
65763
|
+
symbol,
|
|
65764
|
+
raw: true,
|
|
65765
|
+
kind,
|
|
65766
|
+
place: false
|
|
65767
|
+
});
|
|
65768
|
+
config2 = {
|
|
65769
|
+
...config2,
|
|
65770
|
+
...data
|
|
65771
|
+
};
|
|
65772
|
+
console.log("Fetching positions for ", symbol);
|
|
65773
|
+
const positions = await exchange_account.syncAccount({
|
|
65774
|
+
symbol,
|
|
65775
|
+
as_view: true
|
|
65776
|
+
});
|
|
65777
|
+
console.log("Getting long and short positions for ", symbol);
|
|
65778
|
+
const long_position = positions.find((k) => k.kind === "long");
|
|
65779
|
+
const short_position = positions.find((k) => k.kind === "short");
|
|
65780
|
+
console.log("Getting focus position for ", symbol, kind);
|
|
65781
|
+
const focus_position = kind === "long" ? long_position : short_position;
|
|
65782
|
+
const reverse_position = kind === "long" ? short_position : long_position;
|
|
65783
|
+
let reverse_action = null;
|
|
65784
|
+
let reverse_orders_to_buy = [];
|
|
65785
|
+
let reverse_config = null;
|
|
65786
|
+
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
65787
|
+
if (focus_position.quantity > 0) {
|
|
65788
|
+
console.log("Getting details for ", reverse_position.kind);
|
|
65789
|
+
reverse_action = await exchange_account.buildOppositeTrades({
|
|
65790
|
+
symbol,
|
|
65791
|
+
kind
|
|
65792
|
+
});
|
|
65793
|
+
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
65794
|
+
await exchange_account.getPositionConfig({
|
|
65795
|
+
symbol,
|
|
65796
|
+
kind: reverse_action.kind,
|
|
65797
|
+
params: {
|
|
65798
|
+
entry: reverse_action.entry,
|
|
65799
|
+
stop: reverse_action.stop,
|
|
65800
|
+
risk: reverse_action.risk_per_trade,
|
|
65801
|
+
profit_percent: reverse_action.profit_percent,
|
|
65802
|
+
risk_reward: reverse_action.risk_reward
|
|
65803
|
+
}
|
|
65804
|
+
});
|
|
65805
|
+
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
65806
|
+
const reverse_app_config = await exchange_account.buildAppConfig({
|
|
65807
|
+
entry: reverse_action.entry,
|
|
65808
|
+
stop: reverse_action.stop,
|
|
65809
|
+
risk_reward: reverse_action.risk_reward,
|
|
65810
|
+
risk: reverse_action.risk_per_trade,
|
|
65811
|
+
symbol
|
|
65812
|
+
});
|
|
65813
|
+
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
65814
|
+
reverse_orders_to_buy = await exchange_account.placeTrade({
|
|
65815
|
+
symbol,
|
|
65816
|
+
raw: true,
|
|
65817
|
+
kind: reverse_action.kind,
|
|
65818
|
+
place: false
|
|
65819
|
+
});
|
|
65820
|
+
let _reverse_config = {
|
|
65821
|
+
avg: reverse_action.avg,
|
|
65822
|
+
entry: reverse_action.entry,
|
|
65823
|
+
stop: reverse_action.stop,
|
|
65824
|
+
risk_per_trade: reverse_action.risk_per_trade,
|
|
65825
|
+
profit_percent: reverse_action.profit_percent,
|
|
65826
|
+
risk_reward: reverse_action.risk_reward
|
|
65827
|
+
};
|
|
65828
|
+
if (reverse_orders_to_buy.length > 0) {
|
|
65829
|
+
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
65830
|
+
let existing = await exchange_account.placeOppositeTradeAction({
|
|
65831
|
+
symbol,
|
|
65832
|
+
kind: reverse_action.kind,
|
|
65833
|
+
data: _reverse_config
|
|
65834
|
+
});
|
|
65835
|
+
_reverse_config = {
|
|
65836
|
+
...existing,
|
|
65837
|
+
..._reverse_config
|
|
65838
|
+
};
|
|
65839
|
+
}
|
|
65840
|
+
reverse_config = _reverse_config;
|
|
65841
|
+
}
|
|
65842
|
+
if (!reverse_config?.id) {
|
|
65843
|
+
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
65844
|
+
reverse_config = await exchange_account.getPositionConfig({
|
|
65845
|
+
symbol,
|
|
65846
|
+
kind: reverse_action.kind
|
|
65847
|
+
});
|
|
65848
|
+
}
|
|
65849
|
+
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
65850
|
+
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
65851
|
+
const max_size = app_config.max_size * 0.98;
|
|
65852
|
+
if (reverse_config.threshold_qty !== max_size) {
|
|
65853
|
+
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
65854
|
+
follow: true,
|
|
65855
|
+
threshold_qty: max_size
|
|
65856
|
+
});
|
|
65857
|
+
}
|
|
65858
|
+
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
65859
|
+
} else {
|
|
65860
|
+
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
65861
|
+
follow: false
|
|
65862
|
+
});
|
|
65863
|
+
}
|
|
65864
|
+
}
|
|
65865
|
+
return {
|
|
65866
|
+
reverse_config,
|
|
65867
|
+
reverse_action,
|
|
65868
|
+
reverse_orders_to_buy,
|
|
65869
|
+
positions: {
|
|
65870
|
+
long: long_position,
|
|
65871
|
+
short: short_position
|
|
65872
|
+
},
|
|
65873
|
+
orders_to_place,
|
|
65874
|
+
config_details: {
|
|
65875
|
+
app_config,
|
|
65876
|
+
last_value,
|
|
65877
|
+
config: config2,
|
|
65878
|
+
pnl
|
|
65879
|
+
}
|
|
65880
|
+
};
|
|
65881
|
+
}
|
|
65740
65882
|
}
|
|
65741
65883
|
async function initApp(payload) {
|
|
65742
65884
|
const pb = await initPocketBaseClient(payload.db);
|
|
@@ -65871,13 +66013,13 @@ async function getPositions(payload) {
|
|
|
65871
66013
|
const symbol_config = await exchange_account.recomputeSymbolConfig({
|
|
65872
66014
|
symbol: payload.symbol
|
|
65873
66015
|
});
|
|
65874
|
-
const
|
|
66016
|
+
const strategy2 = await exchange_account.getPositionStrategy();
|
|
65875
66017
|
const strategy_config = {
|
|
65876
|
-
tp_percent:
|
|
65877
|
-
short_tp_factor:
|
|
65878
|
-
fee_percent:
|
|
65879
|
-
budget:
|
|
65880
|
-
risk_reward:
|
|
66018
|
+
tp_percent: strategy2?.tp_percent,
|
|
66019
|
+
short_tp_factor: strategy2?.short_tp_factor,
|
|
66020
|
+
fee_percent: strategy2?.fee_percent,
|
|
66021
|
+
budget: strategy2?.budget,
|
|
66022
|
+
risk_reward: strategy2?.risk_reward,
|
|
65881
66023
|
global_config: symbol_config
|
|
65882
66024
|
};
|
|
65883
66025
|
const positions = await exchange_account.syncAccount({
|