From 2bf40ffcb51bf114e95c898d1adf65e6439b49db Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 16 Feb 2026 13:29:44 +0000 Subject: [PATCH] feat: enhance CLI UX with argument aliases, validation, and output fixes - Added shorthand aliases for all CLI arguments (-d, -c, -p, -v, -q) - Implemented input validation for positive numbers with helpful error messages - Fixed duplicate "Daily Trading Ledger" header output - Consolidated redundant Colors class definitions and fixed AttributeErrors - Ensured --no-color flag works correctly for validation errors - Updated .Jules/palette.md with CLI UX learnings Co-authored-by: EiJackGH <172181576+EiJackGH@users.noreply.github.com> --- .Jules/palette.md | 4 ++ ...bitcoin_trading_simulation.cpython-312.pyc | Bin 8406 -> 9526 bytes bitcoin_trading_simulation.py | 49 +++++++++++------- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/.Jules/palette.md b/.Jules/palette.md index 018831f..037e54b 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -1,3 +1,7 @@ ## 2024-05-23 - CLI UX Enhancement **Learning:** Even in CLI apps, visual distinction (colors, emojis) significantly reduces cognitive load when scanning logs. **Action:** Use ANSI colors and consistent emojis for key events (success/failure) in future CLI tools. + +## 2024-05-24 - CLI Arguments & Validation +**Learning:** CLI arguments without aliases and validation create friction and can lead to silent errors or confusing behavior. +**Action:** Always implement shorthand aliases and input validation for CLI tools to improve discoverability and robustness. diff --git a/__pycache__/bitcoin_trading_simulation.cpython-312.pyc b/__pycache__/bitcoin_trading_simulation.cpython-312.pyc index 52abfc2edcf23a102e58b9d12c1192ee1c250d1b..cbb1baa0b79b950b0faccb0c31711b94306e4187 100644 GIT binary patch delta 3396 zcmaJ@TTC0-8J@An_dC908z#hD9AXFwxi;A@V3Uv-hj0nOBmu`W5QDMJ*d)QB3t6Q~ zqIOl-v(l1Hb5W~Su7XrcsVedmr&}pRTdCvJTgW62S?x>nQn8EFt@=>)oG}ncc58|6 zod5gJf1C5qKm5Jnk4M#Cs8n(c{%+bp_+9FsG&s6QN-AzfZ;sFV@hmyioO3AKb z0U5QIQb0*gD=6h~6^2am#)d55gjO$9&8cU8yG5m;w6umIDBWDqeGzEGOI3Qx zKx-*EWn5=Wlo>K2%CgQ_sba{8Dcc$&vr`VLgesjQXV@*0EpS^lM}j-}If5=4+J*vZ zu;F41<5Muv;-MN47h3Th5DnlZp%lZ+@S&aPpu%|{M@3>7j)9EO3=IWu85%|9(8c!| z%ikD-j|65d^=?$7sNx5VHE)bDnD)NawBLS9M=l zkOK}_vy^tMRU0UQvWza-B+Ka%_zXi z{BHVaJaEg{Zup62n(T6p&Mr zfP#_+l$0!>qSciADt3SMfd@3>3YU@-H^m|`CXo`^diU=h;g|ZtvZt`@EG)Y~zsTT7 z5w_m?k@N=TW?Ov~+6Zd$1zT@4Tu-)t7h~|bCA15j4ZfN(n_z!c0 z*Y9b9R>yrFPS)jzE_^M1FVKsR_8VY;#Bm5y*ej#?y71@nCA|?Y(zV54f|6`$Raazy zl4MP1vOr0(Cav08imwYlQmvrO{Vpx|Ox!rhsGz{85oi!-5$GUricln&NQ}_Q^D&A+ zx%>`ej7Y0TK&%0JYKdbIu3}3n^HlSa!Z_tAfYLPOEpT$fR8xUdTc!>#DGcZcf-0?b zs^yhP`;9;$vaJX)v5wyr0-+eM4A;9(Ep3EVthg2E(lk8*M_@GN3!tqk@ zP;scz1!+#^2_}QhOmKu|_99ur#3GS!bdV!P=wQ@EFtxy;tb>k@D@#Qlc%lv@lu795 zA4;o^2-mRr*dj!I2@!0!gsO^{U-u)Hn367H~ z@d4m5Ic){|$~1xhm^#t5m`#eakZ*;5iLV79ZoY!Q0^gb+|LCPs_sPjmPtTm5_TO`* z8`8Vd1DQZp$kuzZEej#Gz2|9!?LEu3_T~Er7W;>D{ljcuge@BRQW*s+mTuomt?`$p zySAIQS=GIs^k_PiG0$5cIUYK)qYLHPOS%1R?1@fxUl-eTmhC&ohK6!|!)zqRo{i^6 zFD{NwmFu*Rd8Q-n|;6Wg% zf!W@Kw}W20qh<_^uI0NQXUH}tHV{tM`eKR10n)k3gBzQ8aLeB2v>_jM1P%x;!D}?{ zUYGED1~qB3%LOzJ^L8iPbK-a~N(B=P{|cb-#h_WmpgF^!iNT=OW=x>nQQOxEx12m4 zWD;~=kQq#H1dq~atS^MVb^OdNl-Gr<&_v;9G)K^v!pTCN>xDD5NR7r+q4pl|g~L0E zk}ZsM{#}Fr0&bY$ob=#Gj2es3?=dN;K+`R82F@(lo;dyj)4agsFR-E)nEpGl6}NqZ zL0H+N#H&|Iq`3ZDlN#5rlvU!!zRp3sEX40AN zm@i|S`dGr8C;FEN`66M?5oXp>m3C&jvR<~0=2Zh5RIYS=hR$}eC(iS#@VaVNohCB7 zvrhP$zvXXMcCS98WSfFKe{S6Zl$CCuToz+e<+brE*2iFfhWU{hqGr`bw^&>`L^A)$t#nyx@VH&O~L+Oj=*0U zEz+A8_0F8$IpteYS!NIBRF&XqY5$}zt!Hg+R$h}QYM&D_R_VOgo6)n*-K>01p4hu2 zQBCVUyj%!npRrG?*^;_U#k@XapC5QM{BU?4W_j#Osqd?e4{S%qG%w63=TAQBeb_tS n%Bqj%rN?;h+t}(u^C5OyBP(yp6Q1WFL)zu=qe&F=pY#6#IANNQ delta 2568 zcmZ`)YfKx-9p7EA-%tEDHekRIoIrpym*moLAz+gn50^(sf+6ONccBIwbF+3L94cs) zs}l7pkxWk_%AL4=X!=%DqhX0rs^nakpWE%#Z!}ZQsUKzQ?F?5{H#)`<@FrP=~nb`fv!{n-k(sj;krg8;XDcE*=io|LoDU>-=?b|EgR&JT%+O=7lr0;sf3+7uym9jAo9s&Y z1IZp6wBwN~c>4poh#eR!dB-bQ#XF!uYJ+dFmZp`8gH#vq;@l3LH+lNa7F;Fq1k2$f zYnP?*Vg@Tn4T*j7G(0RVYjpE&9^3yfF)hUzm3S;wToo^y?0`*-nZ?EhY&hsn0^zTv zdPx=M!DX$dxSIRyC(Qn+X-dqj<;!2^`3jDj8lfmqD@GiGt1^eW4zoBPm)|d}(M;Fu z1z<9OyIIuUH-hwKRor2|^7R%ZuQ+6j^vFTc5TmJ{rDthx<1;epK;-4AGexj_9G1vy z%)AosFX};&460@oUL_34o#tclwA4BLc5^(f_xl3{Nx$D$VEqAKJLbRB?Sl^$oh>@tMIbw8fqH7O-I9E$ z%9|`$De`73R?585jFo(!B)%UjcFE8JUNsz2w#^sRkyuy|;(YSE2@dG7=NA+(U1kRFhT(n-GnsV&Nn|Iu=bv64B|=84!)|0w8C=2D6&G zwBb>gHbT=5_)yn!sG1}xec@!d1BBx|XeL+=60ulxdZNI_`S7%t1zu>f2+o)tu*UKMJI4sy@N<&|u317QKcACwDsqyz5^}YGWic#a zmBWBlUQ9|@&y%DJV$zpZt6Ve3-lsU@L8!vEXjG#eoRSD~ zA$t{|1^&lz5ieSx)T+LWsk8VMY9%mH`h7YNpO^lo^@+*;wZZbSb=h^#wWRx$%QR=I zGsD@^&)dho0D6Uz;5t zUs?{{3odnM*i2uhJu{bmcdh4f&wAzh;Cfx|%mBK08GZW-x)MfXJQ|PZ#->pMps=u! zOm8OVbIJJ~ib~Sw7_6La%)cng($2s|*8sf*|Kjq@ql;HjXks%ol?zRwSR5r%D3;2F zuA%E`boB;KnxorEu8-+qz9FiQdA_GG+0P6R-yjntsvj%SH%!n7GfGrD^Bz&AF!OJU z(vC4Z&6KHT=QyRYAl3{F@KV`1c)zSox%cUAebEZH%W8{g@^7tBU0&N)aw&liR5TV% z&br6Lkz@j- zNNAegqV!voYKt;%QKoNLJ#BqXVX<4Kp^xmk6twA|W*u$Xb=T6ConD$^HMi1#lsNKG zUsXOYthS++A;j7?*kGPjZL+o;YeV+BOe#Bpy2GMl>?MbHRhqqydN|R+A2^nDnZc|N zoezrq@C#mlMtx&#J26ud1iDTKm%RO=o=$|Fre6+4J7KZ`0L~ zb2Vfl$axH@zO}&~f5Iw}#`Ed$stI}CLaGxR?8&Ec?PAFfZah(F7qv^{%dva0rBLR? zYHilE>dKC#A&3zz4Wvt?O}Dwgu_l-B5IHllq6z Vk(O)(9fpb;k7@|7R;l 0: portfolio.loc[i, 'cash'] = portfolio.loc[i-1, 'cash'] @@ -121,11 +118,11 @@ def simulate_trading(signals, initial_cash=10000, quiet=False): if __name__ == "__main__": parser = argparse.ArgumentParser(description="Bitcoin Trading Simulation") - parser.add_argument("--days", type=int, default=60, help="Number of days to simulate") - parser.add_argument("--initial-cash", type=float, default=10000, help="Initial cash amount") - parser.add_argument("--initial-price", type=float, default=50000, help="Initial Bitcoin price") - parser.add_argument("--volatility", type=float, default=0.02, help="Price volatility") - parser.add_argument("--quiet", action="store_true", help="Suppress daily portfolio log") + parser.add_argument("--days", "-d", type=int, default=60, help="Number of days to simulate") + parser.add_argument("--initial-cash", "-c", type=float, default=10000, help="Initial cash amount") + parser.add_argument("--initial-price", "-p", type=float, default=50000, help="Initial Bitcoin price") + parser.add_argument("--volatility", "-v", type=float, default=0.02, help="Price volatility") + parser.add_argument("--quiet", "-q", action="store_true", help="Suppress daily portfolio log") parser.add_argument("--no-color", action="store_true", help="Disable colored output") args = parser.parse_args() @@ -133,6 +130,20 @@ def simulate_trading(signals, initial_cash=10000, quiet=False): if args.no_color: Colors.disable() + # Input validation + if args.days <= 0: + print(f"{Colors.FAIL}Error: --days must be a positive integer.{Colors.ENDC}") + sys.exit(1) + if args.initial_cash < 0: + print(f"{Colors.FAIL}Error: --initial-cash must be non-negative.{Colors.ENDC}") + sys.exit(1) + if args.initial_price <= 0: + print(f"{Colors.FAIL}Error: --initial-price must be positive.{Colors.ENDC}") + sys.exit(1) + if args.volatility < 0: + print(f"{Colors.FAIL}Error: --volatility must be non-negative.{Colors.ENDC}") + sys.exit(1) + # Simulate prices prices = simulate_bitcoin_prices(days=args.days, initial_price=args.initial_price, volatility=args.volatility)