kraken-grid 1.4.5 → 1.4.7

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.
Files changed (51) hide show
  1. package/README.md +72 -66
  2. package/TFCtest/lastFile.txt +1 -0
  3. package/allocation.ts +4 -0
  4. package/balancer.ts +8 -7
  5. package/bot.ts +44 -18
  6. package/dist/TFCtest/callCache.json +2163 -0
  7. package/dist/TFCtest/lastFile.txt +1 -0
  8. package/dist/allocation.js +2 -0
  9. package/dist/allocation.js.map +1 -1
  10. package/dist/balancer.js +8 -6
  11. package/dist/balancer.js.map +1 -1
  12. package/dist/bot.js +41 -16
  13. package/dist/bot.js.map +1 -1
  14. package/dist/gemini.js +72 -36
  15. package/dist/gemini.js.map +1 -1
  16. package/dist/ginit.js +41 -3
  17. package/dist/ginit.js.map +1 -1
  18. package/dist/init.js +37 -0
  19. package/dist/init.js.map +1 -1
  20. package/dist/krak2gem.js +7 -2
  21. package/dist/krak2gem.js.map +1 -1
  22. package/dist/manager.js +4 -3
  23. package/dist/manager.js.map +1 -1
  24. package/dist/reports.js +42 -32
  25. package/dist/reports.js.map +1 -1
  26. package/dist/safestore.js +127 -34
  27. package/dist/safestore.js.map +1 -1
  28. package/dist/savings.js.map +1 -1
  29. package/dist/test/kraken.test.js +2 -1
  30. package/dist/test/kraken.test.js.map +1 -1
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/dist/web.js +4 -4
  33. package/dist/web.js.map +1 -1
  34. package/gemini.ts +405 -0
  35. package/ginit.ts +45 -3
  36. package/init.ts +42 -0
  37. package/krak2gem.ts +7 -3
  38. package/manager.ts +5 -4
  39. package/new-contents.txt +130 -0
  40. package/old-contents.txt +129 -0
  41. package/package.json +3 -1
  42. package/reports.ts +41 -32
  43. package/safestore.ts +138 -36
  44. package/savings.ts +38 -13
  45. package/static/client.js +3 -1
  46. package/test/gem.test.js +28 -7
  47. package/test/kraken.test.ts +2 -1
  48. package/web.ts +5 -5
  49. package/gemini.js +0 -291
  50. package/savings.d.ts +0 -30
  51. package/test/mock-example.test.ts +0 -54
package/README.md CHANGED
@@ -1,63 +1,63 @@
1
- <!-- START doctoc generated TOC please keep comment here to allow auto update -->
2
- <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
1
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
2
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
3
3
  **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
4
-
5
- - [Release Notes for version 1.4](#release-notes-for-version-14)
6
- - [kraken-grid BETA](#kraken-grid-beta)
7
- - [Upgrading](#upgrading)
8
- - [Installation](#installation)
9
- - [Usage](#usage)
10
- - [How the author (Dave) does it for himself and others:](#how-the-author-dave-does-it-for-himself-and-others)
11
- - [Discussion of the `adjust` command.](#discussion-of-the-adjust-command)
12
- - [Web UI](#web-ui)
13
- - [Orders table](#orders-table)
14
- - [Allocation table](#allocation-table)
15
- - [Assets table](#assets-table)
16
- - [Pie Charts](#pie-charts)
17
- - [Changing your password](#changing-your-password)
18
- - [Mistyped passwords](#mistyped-passwords)
19
- - [Command Line Interface](#command-line-interface)
20
- - [Trading](#trading)
21
- - [addlev](#addlev)
22
- - [delev](#delev)
23
- - [buy](#buy)
24
- - [sell](#sell)
25
- - [kill](#kill)
26
- - [limits](#limits)
27
- - [less](#less)
28
- - [more](#more)
29
- - [Information Gathering](#information-gathering)
30
- - [assets](#assets)
31
- - [capGains](#capgains)
32
- - [list [Search]](#list-search)
33
- - [margin](#margin)
34
- - [report](#report)
35
- - [show](#show)
36
- - [verbose](#verbose)
37
- - [web](#web)
38
- - [Bot Management](#bot-management)
39
- - [adjust](#adjust)
40
- - [allocate](#allocate)
41
- - [allocation](#allocation)
42
- - [asset](#asset)
43
- - [auto](#auto)
44
- - [manual](#manual)
45
- - [balance](#balance)
46
- - [notest](#notest)
47
- - [quit](#quit)
48
- - [risky](#risky)
49
- - [refnum](#refnum)
50
- - [reset](#reset)
51
- - [safe](#safe)
52
- - [set](#set)
53
- - [Experimental features (Not Recommended and not well tested)](#experimental-features-not-recommended-and-not-well-tested)
54
- - [ws - EXPERIMENTAL](#ws---experimental)
55
- - [Internals](#internals)
56
- - [Userref](#userref)
57
- - [Partial Execution](#partial-execution)
58
- - [HELP!](#help)
59
-
60
- <!-- END doctoc generated TOC please keep comment here to allow auto update -->
4
+
5
+ - [Release Notes for version 1.4](#release-notes-for-version-14)
6
+ - [kraken-grid BETA](#kraken-grid-beta)
7
+ - [Upgrading](#upgrading)
8
+ - [Installation](#installation)
9
+ - [Usage](#usage)
10
+ - [How the author (Dave) does it for himself and others:](#how-the-author-dave-does-it-for-himself-and-others)
11
+ - [Discussion of the `adjust` command.](#discussion-of-the-adjust-command)
12
+ - [Web UI](#web-ui)
13
+ - [Orders table](#orders-table)
14
+ - [Allocation table](#allocation-table)
15
+ - [Assets table](#assets-table)
16
+ - [Pie Charts](#pie-charts)
17
+ - [Changing your password](#changing-your-password)
18
+ - [Mistyped passwords](#mistyped-passwords)
19
+ - [Command Line Interface](#command-line-interface)
20
+ - [Trading](#trading)
21
+ - [addlev](#addlev)
22
+ - [delev](#delev)
23
+ - [buy](#buy)
24
+ - [sell](#sell)
25
+ - [kill](#kill)
26
+ - [limits](#limits)
27
+ - [less](#less)
28
+ - [more](#more)
29
+ - [Information Gathering](#information-gathering)
30
+ - [assets](#assets)
31
+ - [capGains](#capgains)
32
+ - [list [Search]](#list-search)
33
+ - [margin](#margin)
34
+ - [report](#report)
35
+ - [show](#show)
36
+ - [verbose](#verbose)
37
+ - [web](#web)
38
+ - [Bot Management](#bot-management)
39
+ - [adjust](#adjust)
40
+ - [allocate](#allocate)
41
+ - [allocation](#allocation)
42
+ - [asset](#asset)
43
+ - [auto](#auto)
44
+ - [manual](#manual)
45
+ - [balance](#balance)
46
+ - [notest](#notest)
47
+ - [quit](#quit)
48
+ - [risky](#risky)
49
+ - [refnum](#refnum)
50
+ - [reset](#reset)
51
+ - [safe](#safe)
52
+ - [set](#set)
53
+ - [Experimental features (Not Recommended and not well tested)](#experimental-features-not-recommended-and-not-well-tested)
54
+ - [ws - EXPERIMENTAL](#ws---experimental)
55
+ - [Internals](#internals)
56
+ - [Userref](#userref)
57
+ - [Partial Execution](#partial-execution)
58
+ - [HELP!](#help)
59
+
60
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
61
61
 
62
62
  # Release Notes for version 1.4
63
63
  This project has been converted to Typescript. There are also a few changes on the way to supporting the Gemini Exchange (using gemini-grid instead of kraken-grid). If you use both, lucky you! Kraken asked me to close my account after I got arrested for trading Bitcoin. See https://litmocracy.blogspot.com/2024/06/daves-narrative.html, the beginning of a book about it for more information. I have not tested using both Gemini and Kraken with the same instance. If you want to help, consider [writing some unit tests](https://github.com/dscotese/kraken-grid/issues)!
@@ -72,13 +72,18 @@ This version stores your API key and secret using your password. This informati
72
72
 
73
73
  ## Installation
74
74
  1. Get your API key and secret from Kraken. Otherwise, you will have to go through this process again if you want to run kraken on a machine that doesn't have these keys yet, or if you forget your password.
75
- - 1.1 Click the box in the upper right corner on kraken.com after you log in that has your name in it.
76
- - 1.2 Click the "Security" item in the dropdown box.
77
- - 1.3 Click "API" in the list of options under Security.
78
- - 1.4 Choose the "Add Key" link.
79
- - 1.5 We recommend that you give your key a better description.
80
- - 1.6 Check the "Query Funds" box under "Funds" and all the boxes under "Orders & Trades".
81
- - 1.7 We recommend that you record this set of codes (a key and a private key, called "Secret" in kraken-grid).
75
+ - 1.1 Sign in to your Kraken account and click on the profile icon in the upper right corner.
76
+ - 1.2 Select "Settings" from the dropdown menu.
77
+ - 1.3 Click the "API" tab.
78
+ - 1.4 Click "Create API key".
79
+ - 1.5 We recommend that you give your key a better description (this is now called "Key Description").
80
+ - 1.6 Check the "Query Funds" box under "Funds Permissions" and all the boxes under "Orders & Trades Permissions":
81
+ - Query Open Orders & Trades
82
+ - Query Closed Orders & Trades
83
+ - Modify Orders
84
+ - Cancel/Close Orders
85
+ - 1.7 Click "Generate key".
86
+ - 1.8 IMPORTANT: Copy and save both the API Key and Private Key immediately in a secure location (like a password manager). The Private Key will not be shown again after you leave this page
82
87
  2. Install [NodeJS](https://nodejs.org/)
83
88
  3. Run `npm -g install kraken-grid` from a command line ("Command Prompt", "Terminal Window", or "Shell").
84
89
 
@@ -323,3 +328,4 @@ Because grid orders have conditional closes (at a price I'll call C, for close,
323
328
  This code is messy. It works for me and I didn't want to keep waiting until I cleaned it up to publish it. One of the major motivations I have for publishing it is that as more people use a strategy like "grid trader" to balance their savings, the prices of the cryptos with which they do it will become more stable.
324
329
 
325
330
  All calls to @nothingisdead's [Kraken-API](https://github.com/nothingisdead/npm-kraken-api) (which I have copied and renamed to kraka-djs to add CancelAll) are made through a function I called `kapi` so that any other exchange could be used by updating that funtion to translate Kraken's APIs to those of other exchanges.
331
+
@@ -0,0 +1 @@
1
+ TFCtest/2026-02-20T13-12-20.json
package/allocation.ts CHANGED
@@ -481,6 +481,10 @@ export const AllocCon = async (
481
481
  let str = `\nticker\ttarget\t(adjusted)\t(Range)\t(apct,ppct)\t${compare
482
482
  ? `${compare.name}\tdiff\t`
483
483
  : '\t\t'}Total: ${total}`;
484
+
485
+ // Remove any degenerate asset entries:
486
+ assets = assets.filter(x =>
487
+ (typeof x.ticker == "string" && x.ticker.length > 0));
484
488
 
485
489
  await Promise.all(assets.map(async (a) => {
486
490
  await get(a.ticker); // Forces an update
package/balancer.ts CHANGED
@@ -98,14 +98,15 @@ const Balancer = (config: BalancerConfig): BalancerInstance => {
98
98
  // processes the open orders.
99
99
  // -------------------------------------------------------
100
100
  // We are replacing the grid for p.pair, so let's cancel
101
- // all its orders.
102
- const toCancel = bot.portfolio.O.filter(o => [p.pair, po.altname].includes(o[1].descr.pair))
103
- .map(ae => ae[0]);
104
- console.log(`${bot.FLAGS.safe ? 'NOT ' : ''}Cancelling`, toCancel);
101
+ // all its orders if there are any.
102
+ if(bot.portfolio.O) {
103
+ const toCancel = bot.portfolio.O.filter(o => [p.pair, po.altname].includes(o[1].descr.pair))
104
+ .map(ae => ae[0]);
105
+ console.log(`${bot.FLAGS.safe ? 'NOT ' : ''}Cancelling`, toCancel);
105
106
 
106
- if (!bot.FLAGS.safe && toCancel)
107
- await bot.kill(toCancel);
108
-
107
+ if (!bot.FLAGS.safe && toCancel)
108
+ await bot.kill(toCancel);
109
+ }
109
110
  const Ordered = await bot.order(p.type, p.pair, p.price, p.amt,
110
111
  bot.getLev(bot.portfolio, p.type, p.price, p.amt, po.base, false),
111
112
  0, p.type === 'buy' ? sP : bP); // uref, close
package/bot.ts CHANGED
@@ -314,7 +314,8 @@ export default function Bot(config: any): BotInstance {
314
314
  portfolio.limits = p.limits ? p.limits : [0,-1];
315
315
  portfolio.lastUpdate = p.lastUpdate ? p.lastUpdate : null;
316
316
  portfolio.Allocation = await AllocCon(config,
317
- p.Alloc ? p.Alloc.assets : undefined);
317
+ p.Alloc ? p.Alloc.assets.filter(x =>
318
+ (typeof x.ticker == "string" && x.ticker.length>0)) : undefined);
318
319
  Reports = ReportCon(config.bot);
319
320
  config.report = Reports;
320
321
  }
@@ -450,7 +451,7 @@ export default function Bot(config: any): BotInstance {
450
451
  if(gPrices.length === 0) { // When we have no grid prices, collect orders.
451
452
  console.log("Reading grid from 20 closed orders...");
452
453
  const closed = await moreOrders(20);
453
- const closedIDs = closed?.keysFwd() || [];
454
+ const closedIDs = closed?.keysFwd?.() ?? [];
454
455
  if(closed && closedIDs.length > 0) {
455
456
  let counter = closedIDs.length-1;
456
457
  lCOts = closed?.orders[closedIDs[counter]].closetm || 0;
@@ -463,7 +464,7 @@ export default function Bot(config: any): BotInstance {
463
464
  const cd = new Date(oo.closetm * 1000);
464
465
  let gp:GridPoint | undefined = gPrices.find((x:any) => x.userref===ur); // If we already saw this grid point.
465
466
  if( counter < 5 ) {
466
- console.log(o,ur,op,od.type,od.close,`${cd.getFullYear()}/${1+cd.getMonth()
467
+ console.log(o,ur,op,od.type,oo.vol_exec,od.close,`${cd.getFullYear()}/${1+cd.getMonth()
467
468
  }/${cd.getDate()}`,cd.getHours(),cd.getMinutes(),cd.getSeconds());
468
469
  }
469
470
  counter -= 1;
@@ -647,7 +648,7 @@ export default function Bot(config: any): BotInstance {
647
648
  // Reference Number.
648
649
  async function kill(o,oa:KOrder[]=[]):Promise<APIResponse> {
649
650
  let killed;
650
- if(o === 0) {
651
+ if(o === 0 || /^0$/.test(o)) {
651
652
  const killAll = prompt("Cancel ALL orders? [y/N]");
652
653
  if(/^y/i.test(killAll)) {
653
654
  killed = await kapi('CancelAll');
@@ -837,8 +838,15 @@ console.log("[p,np,dp,t,hp,lp,b,ma,f,tot1,ov,a,a2,t2,t2s]:",
837
838
  if(!c.hasClose) { // If any doesn't have a close, combine them and add one.
838
839
  console.log(421,Object.values(c.ids));
839
840
  const cleared = await kill(c.ids.length>1?c.ids:c.ids[0], portfolio.O);
840
- if( cleared.result.descr === 'Ignored')
841
+ if( cleared?.result?.descr === 'Ignored' || cleared?.result?.count === 0 )
841
842
  throw new Error('No such order(s).');
843
+ if( cleared.result.pending ) {
844
+ // Use QueryOrders to wait until they are gone.
845
+ await sleep(1000);
846
+ let qoRes = await kapi(['QueryOrders',c.ids.join(',')]);
847
+ if( qoRes.result.status != 'canceled' )
848
+ throw new Error('Cancellation took too long.');
849
+ }
842
850
  await order(c.type,sym,price, toDec(c.total,4),
843
851
  c.lev,c.userref,c.open);
844
852
  if(FLAGS.verbose) console.log(425,
@@ -850,7 +858,7 @@ console.log("[p,np,dp,t,hp,lp,b,ma,f,tot1,ov,a,a2,t2,t2s]:",
850
858
  const traded = c.type==='buy' ? 'sold' : 'bought';
851
859
  gp[traded]+=c.total;
852
860
  }
853
- // Do we need to extend the grid?
861
+ // Do we need to [extend] the grid?
854
862
  // If we don't have a buy and a sell, then yes.
855
863
  // --------------------------------------------
856
864
  bs = bSidesP.find(b => b.pair===c.sym); // Was sym+'USD' but #USD Refactor
@@ -873,6 +881,22 @@ console.log("[p,np,dp,t,hp,lp,b,ma,f,tot1,ov,a,a2,t2,t2s]:",
873
881
  let gpsell = Number(gp.sell);
874
882
  let gpbuy = Number(gp.buy);
875
883
  sp = Math.round(10**decimals*gpsell*gpsell/gpbuy)/10**decimals;
884
+ // eslint-disable-next-line no-await-in-loop
885
+ let newVol = -1 * await howMuch(sym, sp);
886
+ if(newVol < 0) {
887
+ // If vol is < 0, use a higher price instead of:
888
+ /* throw new Error(`At ${sp}, you'd have to 'sell' ${
889
+ newVol}, which means we're way out of balance.`);
890
+ return;
891
+ */
892
+ sp = Math.round(10**decimals*gpsell**3/gpbuy**2)/10**decimals;
893
+ // eslint-disable-next-line no-await-in-loop
894
+ newVol = -1 * await howMuch(sym, sp);
895
+ if(newVol < 0) {
896
+ throw new Error(`Even at ${sp}, you'd have to 'sell' ${
897
+ newVol}, which means we're way out of balance.`);
898
+ }
899
+ }
876
900
  // eslint-disable-next-line no-param-reassign
877
901
  c.userref = makeUserRef('sell', c.sym, sp);
878
902
  // We may already have this grid price but the order
@@ -890,13 +914,6 @@ console.log("[p,np,dp,t,hp,lp,b,ma,f,tot1,ov,a,a2,t2,t2s]:",
890
914
  } to close at ${gp.sell}`);
891
915
  }
892
916
  // eslint-disable-next-line no-await-in-loop
893
- const newVol = -1 * await howMuch(sym, sp);
894
- if(newVol < 0) {
895
- console.log("At",sp,"you'd have to 'sell'",
896
- `${newVol}, which means we're way out of balance.`);
897
- return;
898
- }
899
- // eslint-disable-next-line no-await-in-loop
900
917
  await order('sell',c.sym,sp,newVol,
901
918
  getLev(portfolio,'sell',sp,newVol,c.sym,false),c.userref,
902
919
  gpsell);
@@ -907,7 +924,7 @@ console.log("[p,np,dp,t,hp,lp,b,ma,f,tot1,ov,a,a2,t2,t2s]:",
907
924
  gp = gp as GridPoint;
908
925
  let gpsell = Number(gp.sell);
909
926
  let gpbuy = Number(gp.buy);
910
- bp = Math.round(decimals*gpbuy*gpbuy/gpsell)/decimals;
927
+ bp = Math.round(10**decimals*gpbuy*gpbuy/gpsell)/10**decimals;
911
928
  // eslint-disable-next-line no-param-reassign
912
929
  c.userref = makeUserRef('buy', c.sym, bp);
913
930
  // We may already have this grid price but the order
@@ -926,11 +943,20 @@ console.log("[p,np,dp,t,hp,lp,b,ma,f,tot1,ov,a,a2,t2,t2s]:",
926
943
  if(ngp.buy === ngp.sell) throw new Error("Bad Grid Point");
927
944
  }
928
945
  // eslint-disable-next-line no-await-in-loop
929
- const newVol = await howMuch(sym, bp);
946
+ let newVol = await howMuch(sym, bp);
930
947
  if(newVol < 0) {
931
- console.log("At",bp,"you'd have to 'buy'",
932
- `${newVol}, which means we're way out of balance.`);
933
- return;
948
+ // If vol is < 0, use a higher price instead of:
949
+ /* throw new Error(`At ${bp}, you'd have to 'buy' ${
950
+ newVol}, which means we're way out of balance.`);
951
+ return;
952
+ */
953
+ bp = Math.round(10**decimals*gpbuy**3/gpsell**2)/10**decimals;
954
+ // eslint-disable-next-line no-await-in-loop
955
+ newVol = await howMuch(sym, bp);
956
+ if(newVol < 0) {
957
+ throw new Error(`Even at ${bp}, you'd have to 'buy' ${
958
+ newVol}, which means we're way out of balance.`);
959
+ }
934
960
  }
935
961
  // eslint-disable-next-line no-await-in-loop
936
962
  await order('buy',c.sym,bp,newVol,