Compare commits
9 Commits
87385a4e2d
...
5d30325e91
| Author | SHA1 | Date |
|---|---|---|
|
|
5d30325e91 | |
|
|
3f0498f266 | |
|
|
03f83d25d5 | |
|
|
9dbd55c4e4 | |
|
|
00e59057c7 | |
|
|
a92bb87cf3 | |
|
|
81693cc2f7 | |
|
|
729a44a4e5 | |
|
|
15078a713d |
45
README.rst
45
README.rst
|
|
@ -88,57 +88,22 @@ a sane install with `uv`
|
||||||
************************
|
************************
|
||||||
bc why install with `python` when you can faster with `rust` ::
|
bc why install with `python` when you can faster with `rust` ::
|
||||||
|
|
||||||
uv sync
|
uv lock
|
||||||
|
|
||||||
# ^ astral's docs,
|
|
||||||
# https://docs.astral.sh/uv/concepts/projects/sync/
|
|
||||||
|
|
||||||
include all GUIs (ex. for charting)::
|
|
||||||
|
|
||||||
uv sync --extra uis
|
|
||||||
|
|
||||||
AND with all our hacking tools and WIP integrations::
|
|
||||||
|
|
||||||
uv sync --dev --all-extras
|
|
||||||
|
|
||||||
|
|
||||||
Ensure you can run the root-daemon::
|
hacky install on nixos
|
||||||
|
**********************
|
||||||
uv run pikerd [-l info --pdb]
|
|
||||||
|
|
||||||
|
|
||||||
install on nix(os)
|
|
||||||
******************
|
|
||||||
``NixOS`` is our core devs' distro of choice for which we offer
|
``NixOS`` is our core devs' distro of choice for which we offer
|
||||||
a stringently defined development shell envoirment that can currently
|
a stringently defined development shell envoirment that can be loaded with::
|
||||||
be applied in one of 2 ways::
|
|
||||||
|
|
||||||
# ONLY if running on X11
|
|
||||||
nix-shell default.nix
|
nix-shell default.nix
|
||||||
|
|
||||||
Or if you prefer flakes style and a modern DE::
|
|
||||||
|
|
||||||
# ONLY if also running on Wayland
|
|
||||||
nix develop # for default bash
|
|
||||||
nix develop -c uv run xonsh # for @goodboy's preferred sh B)
|
|
||||||
|
|
||||||
|
|
||||||
start a chart
|
start a chart
|
||||||
*************
|
*************
|
||||||
run a realtime OHLCV chart stand-alone::
|
run a realtime OHLCV chart stand-alone::
|
||||||
|
|
||||||
[uv run] piker -l info chart btcusdt.spot.binance xmrusdt.spot.kraken
|
piker -l info chart btcusdt.spot.binance xmrusdt.spot.kraken
|
||||||
|
|
||||||
# ^^^ iff you haven't activated the py-env,
|
|
||||||
# - https://docs.astral.sh/uv/concepts/projects/run/
|
|
||||||
#
|
|
||||||
# in order to create an explicit virt-env see,
|
|
||||||
# - https://docs.astral.sh/uv/concepts/projects/layout/#the-project-environment
|
|
||||||
# - https://docs.astral.sh/uv/pip/environments/
|
|
||||||
#
|
|
||||||
# use $UV_PROJECT_ENVIRONMENT to select any non-`.venv/`
|
|
||||||
# as the venv sudir in the repo's root.
|
|
||||||
# - https://docs.astral.sh/uv/reference/environment/#uv_project_environment
|
|
||||||
|
|
||||||
this runs a chart UI (with 1m sampled OHLCV) and shows 2 spot markets from 2 diff cexes
|
this runs a chart UI (with 1m sampled OHLCV) and shows 2 spot markets from 2 diff cexes
|
||||||
overlayed on the same graph. Use of `piker` without first starting
|
overlayed on the same graph. Use of `piker` without first starting
|
||||||
|
|
|
||||||
37
default.nix
37
default.nix
|
|
@ -11,12 +11,11 @@ let
|
||||||
libxkbcommonStorePath = lib.getLib libxkbcommon;
|
libxkbcommonStorePath = lib.getLib libxkbcommon;
|
||||||
xcbutilcursorStorePath = lib.getLib xcb-util-cursor;
|
xcbutilcursorStorePath = lib.getLib xcb-util-cursor;
|
||||||
|
|
||||||
pypkgs = python313Packages;
|
qtpyStorePath = lib.getLib python312Packages.qtpy;
|
||||||
qtpyStorePath = lib.getLib pypkgs.qtpy;
|
pyqt6StorePath = lib.getLib python312Packages.pyqt6;
|
||||||
pyqt6StorePath = lib.getLib pypkgs.pyqt6;
|
pyqt6SipStorePath = lib.getLib python312Packages.pyqt6-sip;
|
||||||
pyqt6SipStorePath = lib.getLib pypkgs.pyqt6-sip;
|
rapidfuzzStorePath = lib.getLib python312Packages.rapidfuzz;
|
||||||
rapidfuzzStorePath = lib.getLib pypkgs.rapidfuzz;
|
qdarkstyleStorePath = lib.getLib python312Packages.qdarkstyle;
|
||||||
qdarkstyleStorePath = lib.getLib pypkgs.qdarkstyle;
|
|
||||||
|
|
||||||
xorgLibX11StorePath = lib.getLib xorg.libX11;
|
xorgLibX11StorePath = lib.getLib xorg.libX11;
|
||||||
xorgLibxcbStorePath = lib.getLib xorg.libxcb;
|
xorgLibxcbStorePath = lib.getLib xorg.libxcb;
|
||||||
|
|
@ -52,12 +51,12 @@ stdenv.mkDerivation {
|
||||||
xorg.xcbutilrenderutil
|
xorg.xcbutilrenderutil
|
||||||
|
|
||||||
# Python requirements.
|
# Python requirements.
|
||||||
python313
|
python312Full
|
||||||
uv
|
python312Packages.uv
|
||||||
pypkgs.qdarkstyle
|
python312Packages.qdarkstyle
|
||||||
pypkgs.rapidfuzz
|
python312Packages.rapidfuzz
|
||||||
pypkgs.pyqt6
|
python312Packages.pyqt6
|
||||||
pypkgs.qtpy
|
python312Packages.qtpy
|
||||||
];
|
];
|
||||||
src = null;
|
src = null;
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
|
|
@ -114,11 +113,11 @@ stdenv.mkDerivation {
|
||||||
|
|
||||||
export LD_LIBRARY_PATH
|
export LD_LIBRARY_PATH
|
||||||
|
|
||||||
RPDFUZZ_PATH="${rapidfuzzStorePath}/lib/python3.13/site-packages"
|
RPDFUZZ_PATH="${rapidfuzzStorePath}/lib/python3.12/site-packages"
|
||||||
QDRKSTYLE_PATH="${qdarkstyleStorePath}/lib/python3.13/site-packages"
|
QDRKSTYLE_PATH="${qdarkstyleStorePath}/lib/python3.12/site-packages"
|
||||||
QTPY_PATH="${qtpyStorePath}/lib/python3.13/site-packages"
|
QTPY_PATH="${qtpyStorePath}/lib/python3.12/site-packages"
|
||||||
PYQT6_PATH="${pyqt6StorePath}/lib/python3.13/site-packages"
|
PYQT6_PATH="${pyqt6StorePath}/lib/python3.12/site-packages"
|
||||||
PYQT6_SIP_PATH="${pyqt6SipStorePath}/lib/python3.13/site-packages"
|
PYQT6_SIP_PATH="${pyqt6SipStorePath}/lib/python3.12/site-packages"
|
||||||
|
|
||||||
PATCH="$PATCH:$RPDFUZZ_PATH"
|
PATCH="$PATCH:$RPDFUZZ_PATH"
|
||||||
PATCH="$PATCH:$QDRKSTYLE_PATH"
|
PATCH="$PATCH:$QDRKSTYLE_PATH"
|
||||||
|
|
@ -128,8 +127,8 @@ stdenv.mkDerivation {
|
||||||
|
|
||||||
export PATCH
|
export PATCH
|
||||||
|
|
||||||
# install all dev and extras
|
# Install deps
|
||||||
uv sync --dev --all-extras
|
uv lock
|
||||||
|
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
127
flake.lock
127
flake.lock
|
|
@ -1,24 +1,135 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765779637,
|
"lastModified": 1689068808,
|
||||||
"narHash": "sha256-KJ2wa/BLSrTqDjbfyNx70ov/HdgNBCBBSQP3BIzKnv4=",
|
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
||||||
"owner": "nixos",
|
"owner": "numtide",
|
||||||
"repo": "nixpkgs",
|
"repo": "flake-utils",
|
||||||
"rev": "1306659b587dc277866c7b69eb97e5f07864d8c4",
|
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_2": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1689068808,
|
||||||
|
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nix-github-actions": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"poetry2nix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1688870561,
|
||||||
|
"narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-github-actions",
|
||||||
|
"rev": "165b1650b753316aa7f1787f3005a8d2da0f5301",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-github-actions",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1692174805,
|
||||||
|
"narHash": "sha256-xmNPFDi/AUMIxwgOH/IVom55Dks34u1g7sFKKebxUm0=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "caac0eb6bdcad0b32cb2522e03e4002c8975c62e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
"ref": "nixos-unstable",
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"poetry2nix": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_2",
|
||||||
|
"nix-github-actions": "nix-github-actions",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1692048894,
|
||||||
|
"narHash": "sha256-cDw03rso2V4CDc3Mll0cHN+ztzysAvdI8pJ7ybbz714=",
|
||||||
|
"ref": "refs/heads/pyqt6",
|
||||||
|
"rev": "b059ad4c3051f45d6c912e17747aae37a9ec1544",
|
||||||
|
"revCount": 2276,
|
||||||
|
"type": "git",
|
||||||
|
"url": "file:///home/lord_fomo/repos/poetry2nix"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "file:///home/lord_fomo/repos/poetry2nix"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs"
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"poetry2nix": "poetry2nix"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
251
flake.nix
251
flake.nix
|
|
@ -1,103 +1,180 @@
|
||||||
# An "impure" template thx to `pyproject.nix`,
|
# NOTE: to convert to a poetry2nix env like this here are the
|
||||||
# https://pyproject-nix.github.io/pyproject.nix/templates.html#impure
|
# steps:
|
||||||
# https://github.com/pyproject-nix/pyproject.nix/blob/master/templates/impure/flake.nix
|
# - install poetry in your system nix config
|
||||||
{
|
# - convert the repo to use poetry using `poetry init`:
|
||||||
description = "An impure `piker` overlay using `uv` with Nix(OS)";
|
# https://python-poetry.org/docs/basic-usage/#initialising-a-pre-existing-project
|
||||||
|
# - then manually ensuring all deps are converted over:
|
||||||
|
# - add this file to the repo and commit it
|
||||||
|
# -
|
||||||
|
|
||||||
inputs = {
|
# GROKin tips:
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
# - CLI eps are (ostensibly) added via an `entry_points.txt`:
|
||||||
|
# - https://packaging.python.org/en/latest/specifications/entry-points/#file-format
|
||||||
|
# - https://github.com/nix-community/poetry2nix/blob/master/editable.nix#L49
|
||||||
|
{
|
||||||
|
description = "piker: trading gear for hackers (pkged with poetry2nix)";
|
||||||
|
|
||||||
|
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
|
# see https://github.com/nix-community/poetry2nix/tree/master#api
|
||||||
|
inputs.poetry2nix = {
|
||||||
|
# url = "github:nix-community/poetry2nix";
|
||||||
|
# url = "github:K900/poetry2nix/qt5-explicit-deps";
|
||||||
|
url = "/home/lord_fomo/repos/poetry2nix";
|
||||||
|
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs = {
|
||||||
{ nixpkgs, ... }:
|
self,
|
||||||
let
|
nixpkgs,
|
||||||
inherit (nixpkgs) lib;
|
flake-utils,
|
||||||
forAllSystems = lib.genAttrs lib.systems.flakeExposed;
|
poetry2nix,
|
||||||
in
|
}:
|
||||||
{
|
# TODO: build cross-OS and use the `${system}` var thingy..
|
||||||
devShells = forAllSystems (
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
system:
|
let
|
||||||
let
|
# use PWD as sources
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
projectDir = ./.;
|
||||||
|
pyproject = ./pyproject.toml;
|
||||||
|
poetrylock = ./poetry.lock;
|
||||||
|
|
||||||
# do store-path extractions
|
# TODO: port to 3.11 and support both versions?
|
||||||
qt6baseStorePath = lib.getLib pkgs.qt6.qtbase;
|
python = "python3.10";
|
||||||
# ?TODO? can remove below since manual linking not needed?
|
|
||||||
# qt6QtWaylandStorePath = lib.getLib pkgs.qt6.qtwayland;
|
|
||||||
|
|
||||||
# XXX NOTE XXX, for now we overlay specific pkgs via
|
# for more functions and examples.
|
||||||
# a major-version-pinned-`cpython`
|
# inherit
|
||||||
cpython = "python313";
|
# (poetry2nix.legacyPackages.${system})
|
||||||
pypkgs = pkgs."${cpython}Packages";
|
# mkPoetryApplication;
|
||||||
in
|
# pkgs = nixpkgs.legacyPackages.${system};
|
||||||
{
|
|
||||||
default = pkgs.mkShell {
|
|
||||||
|
|
||||||
packages = with pkgs; [
|
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||||
# XXX, ensure sh completions active!
|
lib = pkgs.lib;
|
||||||
bashInteractive
|
p2npkgs = poetry2nix.legacyPackages.x86_64-linux;
|
||||||
bash-completion
|
|
||||||
|
|
||||||
# dev utils
|
# define all pkg overrides per dep, see edgecases.md:
|
||||||
ruff
|
# https://github.com/nix-community/poetry2nix/blob/master/docs/edgecases.md
|
||||||
pypkgs.ruff
|
# TODO: add these into the json file:
|
||||||
|
# https://github.com/nix-community/poetry2nix/blob/master/overrides/build-systems.json
|
||||||
|
pypkgs-build-requirements = {
|
||||||
|
asyncvnc = [ "setuptools" ];
|
||||||
|
eventkit = [ "setuptools" ];
|
||||||
|
ib-insync = [ "setuptools" "flake8" ];
|
||||||
|
msgspec = [ "setuptools"];
|
||||||
|
pdbp = [ "setuptools" ];
|
||||||
|
pyqt6-sip = [ "setuptools" ];
|
||||||
|
tabcompleter = [ "setuptools" ];
|
||||||
|
tractor = [ "setuptools" ];
|
||||||
|
tricycle = [ "setuptools" ];
|
||||||
|
trio-typing = [ "setuptools" ];
|
||||||
|
trio-util = [ "setuptools" ];
|
||||||
|
xonsh = [ "setuptools" ];
|
||||||
|
};
|
||||||
|
|
||||||
qt6.qtwayland
|
# auto-generate override entries
|
||||||
qt6.qtbase
|
p2n-overrides = p2npkgs.defaultPoetryOverrides.extend (self: super:
|
||||||
|
builtins.mapAttrs (package: build-requirements:
|
||||||
|
(builtins.getAttr package super).overridePythonAttrs (old: {
|
||||||
|
buildInputs = (
|
||||||
|
old.buildInputs or [ ]
|
||||||
|
) ++ (
|
||||||
|
builtins.map (
|
||||||
|
pkg: if builtins.isString pkg then builtins.getAttr pkg super else pkg
|
||||||
|
) build-requirements
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) pypkgs-build-requirements
|
||||||
|
);
|
||||||
|
|
||||||
uv
|
# override some ahead-of-time compiled extensions
|
||||||
python313 # ?TODO^ how to set from `cpython` above?
|
# to be built with their wheels.
|
||||||
pypkgs.pyqt6
|
ahot_overrides = p2n-overrides.extend(
|
||||||
pypkgs.pyqt6-sip
|
final: prev: {
|
||||||
pypkgs.qtpy
|
|
||||||
pypkgs.qdarkstyle
|
|
||||||
pypkgs.rapidfuzz
|
|
||||||
];
|
|
||||||
|
|
||||||
shellHook = ''
|
# llvmlite = prev.llvmlite.override {
|
||||||
# unmask to debug **this** dev-shell-hook
|
# preferWheel = false;
|
||||||
# set -e
|
# };
|
||||||
|
|
||||||
# set qt-base/plugin path(s)
|
# TODO: get this workin with p2n and nixpkgs..
|
||||||
QTBASE_PATH="${qt6baseStorePath}/lib"
|
# pyqt6 = prev.pyqt6.override {
|
||||||
QT_PLUGIN_PATH="${qt6baseStorePath}/lib/qt-6/plugins"
|
# preferWheel = true;
|
||||||
QT_QPA_PLATFORM_PLUGIN_PATH="$QT_PLUGIN_PATH/platforms"
|
# };
|
||||||
|
|
||||||
# link in Qt cc lib paths from <nixpkgs>
|
# NOTE: this DOESN'T work atm but after a fix
|
||||||
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$QTBASE_PATH"
|
# to poetry2nix, it will and actually this line
|
||||||
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$QT_PLUGIN_PATH"
|
# won't be needed - thanks @k900:
|
||||||
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$QT_QPA_PLATFORM_PLUGIN_PATH"
|
# https://github.com/nix-community/poetry2nix/pull/1257
|
||||||
|
pyqt5 = prev.pyqt5.override {
|
||||||
|
# withWebkit = false;
|
||||||
|
preferWheel = true;
|
||||||
|
};
|
||||||
|
|
||||||
# link-in c++ stdlib for various AOT-ext-pkgs (numpy, etc.)
|
# see PR from @k900:
|
||||||
LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib:$LD_LIBRARY_PATH"
|
# https://github.com/nix-community/poetry2nix/pull/1257
|
||||||
|
# pyqt5-qt5 = prev.pyqt5-qt5.override {
|
||||||
|
# withWebkit = false;
|
||||||
|
# preferWheel = true;
|
||||||
|
# };
|
||||||
|
|
||||||
export LD_LIBRARY_PATH
|
# TODO: patch in an override for polars to build
|
||||||
|
# from src! See the details likely needed from
|
||||||
# RUNTIME-SETTINGS
|
# the cryptography entry:
|
||||||
#
|
# https://github.com/nix-community/poetry2nix/blob/master/overrides/default.nix#L426-L435
|
||||||
# ------ Qt ------
|
polars = prev.polars.override {
|
||||||
# XXX, unmask to debug qt .so linking/loading deats
|
preferWheel = true;
|
||||||
# export QT_DEBUG_PLUGINS=1
|
};
|
||||||
#
|
}
|
||||||
# ALSO, for *modern linux* DEs,
|
|
||||||
# - maybe set wayland-mode (TODO, parametrtize this!)
|
|
||||||
# * a chosen wayland-mode shell-integration
|
|
||||||
export QT_QPA_PLATFORM="wayland"
|
|
||||||
export QT_WAYLAND_SHELL_INTEGRATION="xdg-shell"
|
|
||||||
|
|
||||||
# ------ uv ------
|
|
||||||
# - always use the ./py313/ venv-subdir
|
|
||||||
export UV_PROJECT_ENVIRONMENT="py313"
|
|
||||||
# sync project-env with all extras
|
|
||||||
uv sync --dev --all-extras --no-group lint
|
|
||||||
|
|
||||||
# ------ TIPS ------
|
|
||||||
# NOTE, to launch the py-venv installed `xonsh` (like @goodboy)
|
|
||||||
# run the `nix develop` cmd with,
|
|
||||||
# >> nix develop -c uv run xonsh
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
# WHY!? -> output-attrs that `nix develop` scans for:
|
||||||
|
# https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop.html#flake-output-attributes
|
||||||
|
in
|
||||||
|
rec {
|
||||||
|
packages = {
|
||||||
|
# piker = poetry2nix.legacyPackages.x86_64-linux.mkPoetryEditablePackage {
|
||||||
|
# editablePackageSources = { piker = ./piker; };
|
||||||
|
|
||||||
|
piker = p2npkgs.mkPoetryApplication {
|
||||||
|
projectDir = projectDir;
|
||||||
|
|
||||||
|
# SEE ABOVE for auto-genned input set, override
|
||||||
|
# buncha deps with extras.. like `setuptools` mostly.
|
||||||
|
# TODO: maybe propose a patch to p2n to show that you
|
||||||
|
# can even do this in the edgecases docs?
|
||||||
|
overrides = ahot_overrides;
|
||||||
|
|
||||||
|
# XXX: won't work on llvmlite..
|
||||||
|
# preferWheels = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# devShells.default = pkgs.mkShell {
|
||||||
|
# projectDir = projectDir;
|
||||||
|
# python = "python3.10";
|
||||||
|
# overrides = ahot_overrides;
|
||||||
|
# inputsFrom = [ self.packages.x86_64-linux.piker ];
|
||||||
|
# packages = packages;
|
||||||
|
# # packages = [ poetry2nix.packages.${system}.poetry ];
|
||||||
|
# };
|
||||||
|
|
||||||
|
# TODO: grok the difference here..
|
||||||
|
# - avoid re-cloning git repos on every develop entry..
|
||||||
|
# - ideally allow hacking on the src code of some deps
|
||||||
|
# (tractor, pyqtgraph, tomlkit, etc.) WITHOUT having to
|
||||||
|
# re-install them every time a change is made.
|
||||||
|
# - boot a usable xonsh inside the poetry virtualenv when
|
||||||
|
# defined via a custom entry point?
|
||||||
|
devShells.default = p2npkgs.mkPoetryEnv {
|
||||||
|
# env = p2npkgs.mkPoetryEnv {
|
||||||
|
projectDir = projectDir;
|
||||||
|
python = pkgs.python310;
|
||||||
|
overrides = ahot_overrides;
|
||||||
|
editablePackageSources = packages;
|
||||||
|
# piker = "./";
|
||||||
|
# tractor = "../tractor/";
|
||||||
|
# }; # wut?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
); # end of .outputs scope
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ from ._mktinfo import (
|
||||||
dec_digits,
|
dec_digits,
|
||||||
digits_to_dec,
|
digits_to_dec,
|
||||||
MktPair,
|
MktPair,
|
||||||
|
Symbol,
|
||||||
unpack_fqme,
|
unpack_fqme,
|
||||||
_derivs as DerivTypes,
|
_derivs as DerivTypes,
|
||||||
)
|
)
|
||||||
|
|
@ -59,6 +60,7 @@ __all__ = [
|
||||||
'Asset',
|
'Asset',
|
||||||
'MktPair',
|
'MktPair',
|
||||||
'Position',
|
'Position',
|
||||||
|
'Symbol',
|
||||||
'Transaction',
|
'Transaction',
|
||||||
'TransactionLedger',
|
'TransactionLedger',
|
||||||
'dec_digits',
|
'dec_digits',
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ import tomli_w # for fast ledger writing
|
||||||
|
|
||||||
from piker.types import Struct
|
from piker.types import Struct
|
||||||
from piker import config
|
from piker import config
|
||||||
from piker.log import get_logger
|
from ..log import get_logger
|
||||||
from .calc import (
|
from .calc import (
|
||||||
iter_by_dt,
|
iter_by_dt,
|
||||||
)
|
)
|
||||||
|
|
@ -239,9 +239,7 @@ class TransactionLedger(UserDict):
|
||||||
|
|
||||||
symcache: SymbologyCache = self._symcache
|
symcache: SymbologyCache = self._symcache
|
||||||
towrite: dict[str, Any] = {}
|
towrite: dict[str, Any] = {}
|
||||||
for tid, txdict in self.tx_sort(
|
for tid, txdict in self.tx_sort(self.data.copy()):
|
||||||
self.data.copy()
|
|
||||||
):
|
|
||||||
# write blank-str expiry for non-expiring assets
|
# write blank-str expiry for non-expiring assets
|
||||||
if (
|
if (
|
||||||
'expiry' in txdict
|
'expiry' in txdict
|
||||||
|
|
@ -379,7 +377,7 @@ def open_trade_ledger(
|
||||||
account,
|
account,
|
||||||
dirpath=_fp,
|
dirpath=_fp,
|
||||||
)
|
)
|
||||||
cpy: dict = ledger_dict.copy()
|
cpy = ledger_dict.copy()
|
||||||
|
|
||||||
# XXX NOTE: if not provided presume we are being called from
|
# XXX NOTE: if not provided presume we are being called from
|
||||||
# sync code and need to maybe run `trio` to generate..
|
# sync code and need to maybe run `trio` to generate..
|
||||||
|
|
@ -408,13 +406,7 @@ def open_trade_ledger(
|
||||||
account=account,
|
account=account,
|
||||||
mod=mod,
|
mod=mod,
|
||||||
symcache=symcache,
|
symcache=symcache,
|
||||||
|
tx_sort=getattr(mod, 'tx_sort', tx_sort),
|
||||||
# NOTE: allow backends to provide custom ledger sorting
|
|
||||||
tx_sort=getattr(
|
|
||||||
mod,
|
|
||||||
'tx_sort',
|
|
||||||
tx_sort,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
yield ledger
|
yield ledger
|
||||||
|
|
|
||||||
|
|
@ -305,8 +305,8 @@ class MktPair(Struct, frozen=True):
|
||||||
# config right?
|
# config right?
|
||||||
# src_type: AssetTypeName
|
# src_type: AssetTypeName
|
||||||
|
|
||||||
# for derivs, info describing contract, egs. strike price, call
|
# for derivs, info describing contract, egs.
|
||||||
# or put, swap type, exercise model, etc.
|
# strike price, call or put, swap type, exercise model, etc.
|
||||||
contract_info: list[str] | None = None
|
contract_info: list[str] | None = None
|
||||||
|
|
||||||
# TODO: rename to sectype since all of these can
|
# TODO: rename to sectype since all of these can
|
||||||
|
|
@ -390,8 +390,8 @@ class MktPair(Struct, frozen=True):
|
||||||
cls,
|
cls,
|
||||||
fqme: str,
|
fqme: str,
|
||||||
|
|
||||||
price_tick: float|str,
|
price_tick: float | str,
|
||||||
size_tick: float|str,
|
size_tick: float | str,
|
||||||
bs_mktid: str,
|
bs_mktid: str,
|
||||||
|
|
||||||
broker: str | None = None,
|
broker: str | None = None,
|
||||||
|
|
@ -677,3 +677,90 @@ def unpack_fqme(
|
||||||
# '.'.join([mkt_ep, venue]),
|
# '.'.join([mkt_ep, venue]),
|
||||||
suffix,
|
suffix,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Symbol(Struct):
|
||||||
|
'''
|
||||||
|
I guess this is some kinda container thing for dealing with
|
||||||
|
all the different meta-data formats from brokers?
|
||||||
|
|
||||||
|
'''
|
||||||
|
key: str
|
||||||
|
|
||||||
|
broker: str = ''
|
||||||
|
venue: str = ''
|
||||||
|
|
||||||
|
# precision descriptors for price and vlm
|
||||||
|
tick_size: Decimal = Decimal('0.01')
|
||||||
|
lot_tick_size: Decimal = Decimal('0.0')
|
||||||
|
|
||||||
|
suffix: str = ''
|
||||||
|
broker_info: dict[str, dict[str, Any]] = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_fqme(
|
||||||
|
cls,
|
||||||
|
fqsn: str,
|
||||||
|
info: dict[str, Any],
|
||||||
|
|
||||||
|
) -> Symbol:
|
||||||
|
broker, mktep, venue, suffix = unpack_fqme(fqsn)
|
||||||
|
tick_size = info.get('price_tick_size', 0.01)
|
||||||
|
lot_size = info.get('lot_tick_size', 0.0)
|
||||||
|
|
||||||
|
return Symbol(
|
||||||
|
broker=broker,
|
||||||
|
key=mktep,
|
||||||
|
tick_size=tick_size,
|
||||||
|
lot_tick_size=lot_size,
|
||||||
|
venue=venue,
|
||||||
|
suffix=suffix,
|
||||||
|
broker_info={broker: info},
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type_key(self) -> str:
|
||||||
|
return list(self.broker_info.values())[0]['asset_type']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tick_size_digits(self) -> int:
|
||||||
|
return float_digits(self.tick_size)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lot_size_digits(self) -> int:
|
||||||
|
return float_digits(self.lot_tick_size)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def price_tick(self) -> Decimal:
|
||||||
|
return Decimal(str(self.tick_size))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size_tick(self) -> Decimal:
|
||||||
|
return Decimal(str(self.lot_tick_size))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def broker(self) -> str:
|
||||||
|
return list(self.broker_info.keys())[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fqme(self) -> str:
|
||||||
|
return maybe_cons_tokens([
|
||||||
|
self.key, # final "pair name" (eg. qqq[/usd], btcusdt)
|
||||||
|
self.venue,
|
||||||
|
self.suffix, # includes expiry and other con info
|
||||||
|
self.broker,
|
||||||
|
])
|
||||||
|
|
||||||
|
def quantize(
|
||||||
|
self,
|
||||||
|
size: float,
|
||||||
|
) -> Decimal:
|
||||||
|
digits = float_digits(self.lot_tick_size)
|
||||||
|
return Decimal(size).quantize(
|
||||||
|
Decimal(f'1.{"0".ljust(digits, "0")}'),
|
||||||
|
rounding=ROUND_HALF_EVEN
|
||||||
|
)
|
||||||
|
|
||||||
|
# NOTE: when cast to `str` return fqme
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.fqme
|
||||||
|
|
|
||||||
|
|
@ -251,16 +251,10 @@ def iter_by_dt(
|
||||||
for k in parsers:
|
for k in parsers:
|
||||||
if (
|
if (
|
||||||
isdict and k in tx
|
isdict and k in tx
|
||||||
or
|
or getattr(tx, k, None)
|
||||||
getattr(tx, k, None)
|
|
||||||
):
|
):
|
||||||
v = (
|
v = tx[k] if isdict else tx.dt
|
||||||
tx[k] if isdict
|
assert v is not None, f'No valid value for `{k}`!?'
|
||||||
else tx.dt
|
|
||||||
)
|
|
||||||
assert v is not None, (
|
|
||||||
f'No valid value for `{k}`!?'
|
|
||||||
)
|
|
||||||
|
|
||||||
# only call parser on the value if not None from
|
# only call parser on the value if not None from
|
||||||
# the `parsers` table above (when NOT using
|
# the `parsers` table above (when NOT using
|
||||||
|
|
@ -275,21 +269,8 @@ def iter_by_dt(
|
||||||
return v
|
return v
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# TODO: move to top?
|
# XXX: should never get here..
|
||||||
from piker.log import get_logger
|
breakpoint()
|
||||||
log = get_logger(__name__)
|
|
||||||
|
|
||||||
# XXX: we should really never get here..
|
|
||||||
# only if a ledger record has no expected sort(able)
|
|
||||||
# field will we likely hit this.. like with ze IB.
|
|
||||||
# if no sortable field just deliver epoch?
|
|
||||||
log.warning(
|
|
||||||
'No (time) sortable field for TXN:\n'
|
|
||||||
f'{tx}\n'
|
|
||||||
)
|
|
||||||
return from_timestamp(0)
|
|
||||||
# breakpoint()
|
|
||||||
|
|
||||||
|
|
||||||
entry: tuple[str, dict] | Transaction
|
entry: tuple[str, dict] | Transaction
|
||||||
for entry in sorted(
|
for entry in sorted(
|
||||||
|
|
|
||||||
|
|
@ -300,8 +300,7 @@ def disect(
|
||||||
assert not df.is_empty()
|
assert not df.is_empty()
|
||||||
|
|
||||||
# muck around in pdbp REPL
|
# muck around in pdbp REPL
|
||||||
# tractor.devx.mk_pdb().set_trace()
|
breakpoint()
|
||||||
# breakpoint()
|
|
||||||
|
|
||||||
# TODO: we REALLY need a better console REPL for this
|
# TODO: we REALLY need a better console REPL for this
|
||||||
# kinda thing..
|
# kinda thing..
|
||||||
|
|
|
||||||
|
|
@ -374,14 +374,9 @@ class Client:
|
||||||
pair: Pair = pair_type(**item)
|
pair: Pair = pair_type(**item)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
e.add_note(
|
e.add_note(
|
||||||
f'\n'
|
"\nDon't panic, prolly stupid binance changed their symbology schema again..\n"
|
||||||
f'New or removed field we need to codify!\n'
|
'Check out their API docs here:\n\n'
|
||||||
f'pair-type: {pair_type!r}\n'
|
'https://binance-docs.github.io/apidocs/spot/en/#exchange-information'
|
||||||
f'\n'
|
|
||||||
f"Don't panic, prolly stupid binance changed their symbology schema again..\n"
|
|
||||||
f'Check out their API docs here:\n'
|
|
||||||
f'\n'
|
|
||||||
f'https://binance-docs.github.io/apidocs/spot/en/#exchange-information\n'
|
|
||||||
)
|
)
|
||||||
raise
|
raise
|
||||||
pair_table[pair.symbol.upper()] = pair
|
pair_table[pair.symbol.upper()] = pair
|
||||||
|
|
|
||||||
|
|
@ -97,13 +97,6 @@ class Pair(Struct, frozen=True, kw_only=True):
|
||||||
baseAsset: str
|
baseAsset: str
|
||||||
baseAssetPrecision: int
|
baseAssetPrecision: int
|
||||||
|
|
||||||
permissionSets: list[list[str]]
|
|
||||||
|
|
||||||
# https://developers.binance.com/docs/binance-spot-api-docs#2025-08-26
|
|
||||||
# will become non-optional 2025-08-28?
|
|
||||||
# https://developers.binance.com/docs/binance-spot-api-docs#future-changes
|
|
||||||
pegInstructionsAllowed: bool|None = None
|
|
||||||
|
|
||||||
filters: dict[
|
filters: dict[
|
||||||
str,
|
str,
|
||||||
str | int | float,
|
str | int | float,
|
||||||
|
|
@ -149,11 +142,7 @@ class SpotPair(Pair, frozen=True):
|
||||||
defaultSelfTradePreventionMode: str
|
defaultSelfTradePreventionMode: str
|
||||||
allowedSelfTradePreventionModes: list[str]
|
allowedSelfTradePreventionModes: list[str]
|
||||||
permissions: list[str]
|
permissions: list[str]
|
||||||
|
permissionSets: list[list[str]]
|
||||||
# can the paint botz creat liq gaps even easier on this asset?
|
|
||||||
# Bp
|
|
||||||
# https://developers.binance.com/docs/binance-spot-api-docs/faqs/order_amend_keep_priority
|
|
||||||
amendAllowed: bool
|
|
||||||
|
|
||||||
# NOTE: see `.data._symcache.SymbologyCache.load()` for why
|
# NOTE: see `.data._symcache.SymbologyCache.load()` for why
|
||||||
ns_path: str = 'piker.brokers.binance:SpotPair'
|
ns_path: str = 'piker.brokers.binance:SpotPair'
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ from piker.brokers._util import get_logger
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .api import Client
|
from .api import Client
|
||||||
from ib_insync import IB
|
from ib_insync import IB
|
||||||
import i3ipc
|
|
||||||
|
|
||||||
log = get_logger('piker.brokers.ib')
|
log = get_logger('piker.brokers.ib')
|
||||||
|
|
||||||
|
|
@ -49,37 +48,6 @@ _reset_tech: Literal[
|
||||||
] = 'vnc'
|
] = 'vnc'
|
||||||
|
|
||||||
|
|
||||||
no_setup_msg:str = (
|
|
||||||
'No data reset hack test setup for {vnc_sockaddr}!\n'
|
|
||||||
'See config setup tips @\n'
|
|
||||||
'https://github.com/pikers/piker/tree/master/piker/brokers/ib'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def try_xdo_manual(
|
|
||||||
vnc_sockaddr: str,
|
|
||||||
):
|
|
||||||
'''
|
|
||||||
Do the "manual" `xdo`-based screen switch + click
|
|
||||||
combo since apparently the `asyncvnc` client ain't workin..
|
|
||||||
|
|
||||||
Note this is only meant as a backup method for Xorg users,
|
|
||||||
ideally you can use a real vnc client and the `vnc_click_hack()`
|
|
||||||
impl!
|
|
||||||
|
|
||||||
'''
|
|
||||||
global _reset_tech
|
|
||||||
try:
|
|
||||||
i3ipc_xdotool_manual_click_hack()
|
|
||||||
_reset_tech = 'i3ipc_xdotool'
|
|
||||||
return True
|
|
||||||
except OSError:
|
|
||||||
log.exception(
|
|
||||||
no_setup_msg.format(vnc_sockaddr)
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
async def data_reset_hack(
|
async def data_reset_hack(
|
||||||
# vnc_host: str,
|
# vnc_host: str,
|
||||||
client: Client,
|
client: Client,
|
||||||
|
|
@ -122,9 +90,15 @@ async def data_reset_hack(
|
||||||
vnc_port: int
|
vnc_port: int
|
||||||
vnc_sockaddr: tuple[str] | None = client.conf.get('vnc_addrs')
|
vnc_sockaddr: tuple[str] | None = client.conf.get('vnc_addrs')
|
||||||
|
|
||||||
|
no_setup_msg:str = (
|
||||||
|
f'No data reset hack test setup for {vnc_sockaddr}!\n'
|
||||||
|
'See config setup tips @\n'
|
||||||
|
'https://github.com/pikers/piker/tree/master/piker/brokers/ib'
|
||||||
|
)
|
||||||
|
|
||||||
if not vnc_sockaddr:
|
if not vnc_sockaddr:
|
||||||
log.warning(
|
log.warning(
|
||||||
no_setup_msg.format(vnc_sockaddr)
|
no_setup_msg
|
||||||
+
|
+
|
||||||
'REQUIRES A `vnc_addrs: array` ENTRY'
|
'REQUIRES A `vnc_addrs: array` ENTRY'
|
||||||
)
|
)
|
||||||
|
|
@ -145,38 +119,27 @@ async def data_reset_hack(
|
||||||
port=vnc_port,
|
port=vnc_port,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except (
|
except OSError:
|
||||||
OSError, # no VNC server avail..
|
if vnc_host != 'localhost':
|
||||||
PermissionError, # asyncvnc pw fail..
|
log.warning(no_setup_msg)
|
||||||
):
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import i3ipc # noqa (since a deps dynamic check)
|
import i3ipc # noqa (since a deps dynamic check)
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
log.warning(
|
log.warning(no_setup_msg)
|
||||||
no_setup_msg.format(vnc_sockaddr)
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if vnc_host not in {
|
try:
|
||||||
'localhost',
|
i3ipc_xdotool_manual_click_hack()
|
||||||
'127.0.0.1',
|
_reset_tech = 'i3ipc_xdotool'
|
||||||
}:
|
return True
|
||||||
focussed, matches = i3ipc_fin_wins_titled()
|
except OSError:
|
||||||
if not matches:
|
log.exception(no_setup_msg)
|
||||||
log.warning(
|
return False
|
||||||
no_setup_msg.format(vnc_sockaddr)
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
try_xdo_manual(vnc_sockaddr)
|
|
||||||
|
|
||||||
# localhost but no vnc-client or it borked..
|
|
||||||
else:
|
|
||||||
try_xdo_manual(vnc_sockaddr)
|
|
||||||
|
|
||||||
case 'i3ipc_xdotool':
|
case 'i3ipc_xdotool':
|
||||||
try_xdo_manual(vnc_sockaddr)
|
i3ipc_xdotool_manual_click_hack()
|
||||||
# i3ipc_xdotool_manual_click_hack()
|
|
||||||
|
|
||||||
case _ as tech:
|
case _ as tech:
|
||||||
raise RuntimeError(f'{tech} is not supported for reset tech!?')
|
raise RuntimeError(f'{tech} is not supported for reset tech!?')
|
||||||
|
|
@ -215,9 +178,9 @@ async def vnc_click_hack(
|
||||||
host,
|
host,
|
||||||
port=port,
|
port=port,
|
||||||
|
|
||||||
# TODO: doesn't work?
|
# TODO: doesn't work see:
|
||||||
# see, https://github.com/barneygale/asyncvnc/issues/7
|
# https://github.com/barneygale/asyncvnc/issues/7
|
||||||
password='doggy',
|
# password='ibcansmbz',
|
||||||
|
|
||||||
) as client:
|
) as client:
|
||||||
|
|
||||||
|
|
@ -231,103 +194,70 @@ async def vnc_click_hack(
|
||||||
client.keyboard.press('Ctrl', 'Alt', key) # keys are stacked
|
client.keyboard.press('Ctrl', 'Alt', key) # keys are stacked
|
||||||
|
|
||||||
|
|
||||||
def i3ipc_fin_wins_titled(
|
|
||||||
titles: list[str] = [
|
|
||||||
'Interactive Brokers', # tws running in i3
|
|
||||||
'IB Gateway', # gw running in i3
|
|
||||||
# 'IB', # gw running in i3 (newer version?)
|
|
||||||
|
|
||||||
# !TODO, remote vnc instance
|
|
||||||
# -[ ] something in title (or other Con-props) that indicates
|
|
||||||
# this is explicitly for ibrk sw?
|
|
||||||
# |_[ ] !can use modden spawn eventually!
|
|
||||||
'TigerVNC',
|
|
||||||
# 'vncviewer', # the terminal..
|
|
||||||
],
|
|
||||||
) -> tuple[
|
|
||||||
i3ipc.Con, # orig focussed win
|
|
||||||
list[tuple[str, i3ipc.Con]], # matching wins by title
|
|
||||||
]:
|
|
||||||
'''
|
|
||||||
Attempt to find a local-DE window titled with an entry in
|
|
||||||
`titles`.
|
|
||||||
|
|
||||||
If found deliver the current focussed window and all matching
|
|
||||||
`i3ipc.Con`s in a list.
|
|
||||||
|
|
||||||
'''
|
|
||||||
import i3ipc
|
|
||||||
ipc = i3ipc.Connection()
|
|
||||||
|
|
||||||
# TODO: might be worth offering some kinda api for grabbing
|
|
||||||
# the window id from the pid?
|
|
||||||
# https://stackoverflow.com/a/2250879
|
|
||||||
tree = ipc.get_tree()
|
|
||||||
focussed: i3ipc.Con = tree.find_focused()
|
|
||||||
|
|
||||||
matches: list[i3ipc.Con] = []
|
|
||||||
for name in titles:
|
|
||||||
results = tree.find_titled(name)
|
|
||||||
print(f'results for {name}: {results}')
|
|
||||||
if results:
|
|
||||||
con = results[0]
|
|
||||||
matches.append((
|
|
||||||
name,
|
|
||||||
con,
|
|
||||||
))
|
|
||||||
|
|
||||||
return (
|
|
||||||
focussed,
|
|
||||||
matches,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def i3ipc_xdotool_manual_click_hack() -> None:
|
def i3ipc_xdotool_manual_click_hack() -> None:
|
||||||
'''
|
'''
|
||||||
Do the data reset hack but expecting a local X-window using `xdotool`.
|
Do the data reset hack but expecting a local X-window using `xdotool`.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
focussed, matches = i3ipc_fin_wins_titled()
|
import i3ipc
|
||||||
orig_win_id = focussed.window
|
i3 = i3ipc.Connection()
|
||||||
|
|
||||||
|
# TODO: might be worth offering some kinda api for grabbing
|
||||||
|
# the window id from the pid?
|
||||||
|
# https://stackoverflow.com/a/2250879
|
||||||
|
t = i3.get_tree()
|
||||||
|
|
||||||
|
orig_win_id = t.find_focused().window
|
||||||
|
|
||||||
|
# for tws
|
||||||
|
win_names: list[str] = [
|
||||||
|
'Interactive Brokers', # tws running in i3
|
||||||
|
'IB Gateway', # gw running in i3
|
||||||
|
# 'IB', # gw running in i3 (newer version?)
|
||||||
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for name, con in matches:
|
for name in win_names:
|
||||||
print(f'Resetting data feed for {name}')
|
results = t.find_titled(name)
|
||||||
win_id = str(con.window)
|
print(f'results for {name}: {results}')
|
||||||
w, h = con.rect.width, con.rect.height
|
if results:
|
||||||
|
con = results[0]
|
||||||
|
print(f'Resetting data feed for {name}')
|
||||||
|
win_id = str(con.window)
|
||||||
|
w, h = con.rect.width, con.rect.height
|
||||||
|
|
||||||
# TODO: seems to be a few libs for python but not sure
|
# TODO: seems to be a few libs for python but not sure
|
||||||
# if they support all the sub commands we need, order of
|
# if they support all the sub commands we need, order of
|
||||||
# most recent commit history:
|
# most recent commit history:
|
||||||
# https://github.com/rr-/pyxdotool
|
# https://github.com/rr-/pyxdotool
|
||||||
# https://github.com/ShaneHutter/pyxdotool
|
# https://github.com/ShaneHutter/pyxdotool
|
||||||
# https://github.com/cphyc/pyxdotool
|
# https://github.com/cphyc/pyxdotool
|
||||||
|
|
||||||
# TODO: only run the reconnect (2nd) kc on a detected
|
# TODO: only run the reconnect (2nd) kc on a detected
|
||||||
# disconnect?
|
# disconnect?
|
||||||
for key_combo, timeout in [
|
for key_combo, timeout in [
|
||||||
# only required if we need a connection reset.
|
# only required if we need a connection reset.
|
||||||
# ('ctrl+alt+r', 12),
|
# ('ctrl+alt+r', 12),
|
||||||
# data feed reset.
|
# data feed reset.
|
||||||
('ctrl+alt+f', 6)
|
('ctrl+alt+f', 6)
|
||||||
]:
|
]:
|
||||||
subprocess.call([
|
subprocess.call([
|
||||||
'xdotool',
|
'xdotool',
|
||||||
'windowactivate', '--sync', win_id,
|
'windowactivate', '--sync', win_id,
|
||||||
|
|
||||||
# move mouse to bottom left of window (where
|
# move mouse to bottom left of window (where
|
||||||
# there should be nothing to click).
|
# there should be nothing to click).
|
||||||
'mousemove_relative', '--sync', str(w-4), str(h-4),
|
'mousemove_relative', '--sync', str(w-4), str(h-4),
|
||||||
|
|
||||||
# NOTE: we may need to stick a `--retry 3` in here..
|
# NOTE: we may need to stick a `--retry 3` in here..
|
||||||
'click', '--window', win_id,
|
'click', '--window', win_id,
|
||||||
'--repeat', '3', '1',
|
'--repeat', '3', '1',
|
||||||
|
|
||||||
# hackzorzes
|
# hackzorzes
|
||||||
'key', key_combo,
|
'key', key_combo,
|
||||||
],
|
],
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
)
|
)
|
||||||
|
|
||||||
# re-activate and focus original window
|
# re-activate and focus original window
|
||||||
subprocess.call([
|
subprocess.call([
|
||||||
|
|
|
||||||
|
|
@ -1241,47 +1241,32 @@ async def deliver_trade_events(
|
||||||
# never relay errors for non-broker related issues
|
# never relay errors for non-broker related issues
|
||||||
# https://interactivebrokers.github.io/tws-api/message_codes.html
|
# https://interactivebrokers.github.io/tws-api/message_codes.html
|
||||||
code: int = err['error_code']
|
code: int = err['error_code']
|
||||||
reason: str = err['reason']
|
if code in {
|
||||||
reqid: str = str(err['reqid'])
|
200, # uhh
|
||||||
|
|
||||||
# "Warning:" msg codes,
|
|
||||||
# https://interactivebrokers.github.io/tws-api/message_codes.html#warning_codes
|
|
||||||
# - 2109: 'Outside Regular Trading Hours'
|
|
||||||
if 'Warning:' in reason:
|
|
||||||
log.warning(
|
|
||||||
f'Order-API-warning: {code!r}\n'
|
|
||||||
f'reqid: {reqid!r}\n'
|
|
||||||
f'\n'
|
|
||||||
f'{pformat(err)}\n'
|
|
||||||
# ^TODO? should we just print the `reason`
|
|
||||||
# not the full `err`-dict?
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# XXX known special (ignore) cases
|
|
||||||
elif code in {
|
|
||||||
200, # uhh.. ni idea
|
|
||||||
|
|
||||||
# hist pacing / connectivity
|
# hist pacing / connectivity
|
||||||
162,
|
162,
|
||||||
165,
|
165,
|
||||||
|
|
||||||
|
# WARNING codes:
|
||||||
|
# https://interactivebrokers.github.io/tws-api/message_codes.html#warning_codes
|
||||||
|
# Attribute 'Outside Regular Trading Hours' is
|
||||||
|
# " 'ignored based on the order type and
|
||||||
|
# destination. PlaceOrder is now ' 'being
|
||||||
|
# processed.',
|
||||||
|
2109,
|
||||||
|
|
||||||
# XXX: lol this isn't even documented..
|
# XXX: lol this isn't even documented..
|
||||||
# 'No market data during competing live session'
|
# 'No market data during competing live session'
|
||||||
1669,
|
1669,
|
||||||
}:
|
}:
|
||||||
log.error(
|
|
||||||
f'Order-API-error which is non-cancel-causing ?!\n'
|
|
||||||
f'\n'
|
|
||||||
f'{pformat(err)}\n'
|
|
||||||
)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
reqid: str = str(err['reqid'])
|
||||||
|
reason: str = err['reason']
|
||||||
|
|
||||||
if err['reqid'] == -1:
|
if err['reqid'] == -1:
|
||||||
log.error(
|
log.error(f'TWS external order error:\n{pformat(err)}')
|
||||||
f'TWS external order error ??\n'
|
|
||||||
f'{pformat(err)}\n'
|
|
||||||
)
|
|
||||||
|
|
||||||
flow: dict = dict(
|
flow: dict = dict(
|
||||||
flows.get(reqid)
|
flows.get(reqid)
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ import urllib.parse
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import base64
|
import base64
|
||||||
import tractor
|
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
from piker import config
|
from piker import config
|
||||||
|
|
@ -373,7 +372,8 @@ class Client:
|
||||||
# 1658347714, 'status': 'Success'}]}
|
# 1658347714, 'status': 'Success'}]}
|
||||||
|
|
||||||
if xfers:
|
if xfers:
|
||||||
await tractor.pause()
|
import tractor
|
||||||
|
await tractor.pp()
|
||||||
|
|
||||||
trans: dict[str, Transaction] = {}
|
trans: dict[str, Transaction] = {}
|
||||||
for entry in xfers:
|
for entry in xfers:
|
||||||
|
|
@ -501,8 +501,7 @@ class Client:
|
||||||
for xkey, data in resp['result'].items():
|
for xkey, data in resp['result'].items():
|
||||||
|
|
||||||
# NOTE: always cache in pairs tables for faster lookup
|
# NOTE: always cache in pairs tables for faster lookup
|
||||||
with tractor.devx.maybe_open_crash_handler(): # as bxerr:
|
pair = Pair(xname=xkey, **data)
|
||||||
pair = Pair(xname=xkey, **data)
|
|
||||||
|
|
||||||
# register the above `Pair` structs for all
|
# register the above `Pair` structs for all
|
||||||
# key-sets/monikers: a set of 4 (frickin) tables
|
# key-sets/monikers: a set of 4 (frickin) tables
|
||||||
|
|
|
||||||
|
|
@ -175,8 +175,9 @@ async def handle_order_requests(
|
||||||
|
|
||||||
case {
|
case {
|
||||||
'account': 'kraken.spot' as account,
|
'account': 'kraken.spot' as account,
|
||||||
'action': 'buy'|'sell',
|
'action': action,
|
||||||
}:
|
} if action in {'buy', 'sell'}:
|
||||||
|
|
||||||
# validate
|
# validate
|
||||||
order = BrokerdOrder(**msg)
|
order = BrokerdOrder(**msg)
|
||||||
|
|
||||||
|
|
@ -261,12 +262,6 @@ async def handle_order_requests(
|
||||||
} | extra
|
} | extra
|
||||||
|
|
||||||
log.info(f'Submitting WS order request:\n{pformat(req)}')
|
log.info(f'Submitting WS order request:\n{pformat(req)}')
|
||||||
|
|
||||||
# NOTE HOWTO, debug order requests
|
|
||||||
#
|
|
||||||
# if 'XRP' in pair:
|
|
||||||
# await tractor.pause()
|
|
||||||
|
|
||||||
await ws.send_msg(req)
|
await ws.send_msg(req)
|
||||||
|
|
||||||
# placehold for sanity checking in relay loop
|
# placehold for sanity checking in relay loop
|
||||||
|
|
@ -1090,8 +1085,6 @@ async def handle_order_updates(
|
||||||
f'Failed to {action} order {reqid}:\n'
|
f'Failed to {action} order {reqid}:\n'
|
||||||
f'{errmsg}'
|
f'{errmsg}'
|
||||||
)
|
)
|
||||||
# if tractor._state.debug_mode():
|
|
||||||
# await tractor.pause()
|
|
||||||
|
|
||||||
symbol: str = 'N/A'
|
symbol: str = 'N/A'
|
||||||
if chain := apiflows.get(reqid):
|
if chain := apiflows.get(reqid):
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ Symbology defs and search.
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import tractor
|
import tractor
|
||||||
|
from rapidfuzz import process as fuzzy
|
||||||
|
|
||||||
from piker._cacheables import (
|
from piker._cacheables import (
|
||||||
async_lifo_cache,
|
async_lifo_cache,
|
||||||
|
|
@ -40,13 +41,8 @@ from piker.accounting._mktinfo import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# https://www.kraken.com/features/api#get-tradable-pairs
|
||||||
class Pair(Struct):
|
class Pair(Struct):
|
||||||
'''
|
|
||||||
A tradable asset pair as schema-defined by,
|
|
||||||
|
|
||||||
https://docs.kraken.com/api/docs/rest-api/get-tradable-asset-pairs
|
|
||||||
|
|
||||||
'''
|
|
||||||
xname: str # idiotic bs_mktid equiv i guess?
|
xname: str # idiotic bs_mktid equiv i guess?
|
||||||
altname: str # alternate pair name
|
altname: str # alternate pair name
|
||||||
wsname: str # WebSocket pair name (if available)
|
wsname: str # WebSocket pair name (if available)
|
||||||
|
|
@ -57,6 +53,7 @@ class Pair(Struct):
|
||||||
lot: str # volume lot size
|
lot: str # volume lot size
|
||||||
|
|
||||||
cost_decimals: int
|
cost_decimals: int
|
||||||
|
costmin: float
|
||||||
pair_decimals: int # scaling decimal places for pair
|
pair_decimals: int # scaling decimal places for pair
|
||||||
lot_decimals: int # scaling decimal places for volume
|
lot_decimals: int # scaling decimal places for volume
|
||||||
|
|
||||||
|
|
@ -82,7 +79,6 @@ class Pair(Struct):
|
||||||
tick_size: float # min price step size
|
tick_size: float # min price step size
|
||||||
status: str
|
status: str
|
||||||
|
|
||||||
costmin: str|None = None # XXX, only some mktpairs?
|
|
||||||
short_position_limit: float = 0
|
short_position_limit: float = 0
|
||||||
long_position_limit: float = float('inf')
|
long_position_limit: float = float('inf')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -740,7 +740,7 @@ async def sample_and_broadcast(
|
||||||
|
|
||||||
log.warning(
|
log.warning(
|
||||||
f'Feed OVERRUN {sub_key}'
|
f'Feed OVERRUN {sub_key}'
|
||||||
f'@{bus.brokername} -> \n'
|
'@{bus.brokername} -> \n'
|
||||||
f'feed @ {chan.uid}\n'
|
f'feed @ {chan.uid}\n'
|
||||||
f'throttle = {throttle} Hz'
|
f'throttle = {throttle} Hz'
|
||||||
)
|
)
|
||||||
|
|
|
||||||
124
pyproject.toml
124
pyproject.toml
|
|
@ -23,7 +23,7 @@ name = "piker"
|
||||||
version = "0.1.0a0dev0"
|
version = "0.1.0a0dev0"
|
||||||
description = "trading gear for hackers"
|
description = "trading gear for hackers"
|
||||||
authors = [{ name = "Tyler Goodlet", email = "goodboy_foss@protonmail.com" }]
|
authors = [{ name = "Tyler Goodlet", email = "goodboy_foss@protonmail.com" }]
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12, <3.13"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
readme = "README.rst"
|
readme = "README.rst"
|
||||||
keywords = [
|
keywords = [
|
||||||
|
|
@ -39,8 +39,8 @@ classifiers = [
|
||||||
"Operating System :: POSIX :: Linux",
|
"Operating System :: POSIX :: Linux",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
"Programming Language :: Python :: 3 :: Only",
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python :: 3.13",
|
|
||||||
"Intended Audience :: Financial and Insurance Industry",
|
"Intended Audience :: Financial and Insurance Industry",
|
||||||
"Intended Audience :: Science/Research",
|
"Intended Audience :: Science/Research",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
|
|
@ -49,13 +49,13 @@ classifiers = [
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-generator >=1.10, <2.0.0",
|
"async-generator >=1.10, <2.0.0",
|
||||||
"attrs >=23.1.0, <24.0.0",
|
"attrs >=23.1.0, <24.0.0",
|
||||||
"bidict >=0.23.1",
|
"bidict >=0.22.1, <0.23.0",
|
||||||
"colorama >=0.4.6, <0.5.0",
|
"colorama >=0.4.6, <0.5.0",
|
||||||
"colorlog >=6.7.0, <7.0.0",
|
"colorlog >=6.7.0, <7.0.0",
|
||||||
"ib-insync >=0.9.86, <0.10.0",
|
"ib-insync >=0.9.86, <0.10.0",
|
||||||
"numpy>=2.0",
|
"numba >=0.59.0, <0.60.0",
|
||||||
"polars >=0.20.6",
|
"numpy >=1.25, <2.0",
|
||||||
"polars-fuzzy-match>=0.1.5",
|
"polars >=0.18.13, <0.19.0",
|
||||||
"pygments >=2.16.1, <3.0.0",
|
"pygments >=2.16.1, <3.0.0",
|
||||||
"rich >=13.5.2, <14.0.0",
|
"rich >=13.5.2, <14.0.0",
|
||||||
"tomli >=2.0.1, <3.0.0",
|
"tomli >=2.0.1, <3.0.0",
|
||||||
|
|
@ -63,27 +63,21 @@ dependencies = [
|
||||||
"trio-util >=0.7.0, <0.8.0",
|
"trio-util >=0.7.0, <0.8.0",
|
||||||
"trio-websocket >=0.10.3, <0.11.0",
|
"trio-websocket >=0.10.3, <0.11.0",
|
||||||
"typer >=0.9.0, <1.0.0",
|
"typer >=0.9.0, <1.0.0",
|
||||||
"trio >=0.27",
|
"rapidfuzz >=3.5.2, <4.0.0",
|
||||||
"pendulum",
|
"pdbp >=1.5.0, <2.0.0",
|
||||||
|
"trio >=0.24, <0.25",
|
||||||
|
"pendulum >=3.0.0, <4.0.0",
|
||||||
"httpx >=0.27.0, <0.28.0",
|
"httpx >=0.27.0, <0.28.0",
|
||||||
"cryptofeed >=2.4.0, <3.0.0",
|
"cryptofeed >=2.4.0, <3.0.0",
|
||||||
"pyarrow>=18.0.0",
|
"pyarrow >=17.0.0, <18.0.0",
|
||||||
"websockets ==12.0",
|
"websockets ==12.0",
|
||||||
"msgspec>=0.19.0,<0.20",
|
"msgspec",
|
||||||
"tractor",
|
"tractor",
|
||||||
|
"asyncvnc",
|
||||||
"tomlkit",
|
"tomlkit",
|
||||||
"trio-typing>=0.10.0",
|
|
||||||
"numba>=0.61.0",
|
|
||||||
"pyvnc",
|
|
||||||
]
|
]
|
||||||
# ------ dependencies ------
|
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
# TODO: add an `--only daemon` group for running non-ui / pikerd
|
|
||||||
# service tree in distributed mode B)
|
|
||||||
# https://docs.astral.sh/uv/concepts/projects/dependencies/#optional-dependencies
|
|
||||||
|
|
||||||
[dependency-groups]
|
|
||||||
uis = [
|
uis = [
|
||||||
# https://docs.astral.sh/uv/concepts/projects/dependencies/#optional-dependencies
|
# https://docs.astral.sh/uv/concepts/projects/dependencies/#optional-dependencies
|
||||||
# TODO: make sure the levenshtein shit compiles on nix..
|
# TODO: make sure the levenshtein shit compiles on nix..
|
||||||
|
|
@ -96,11 +90,12 @@ uis = [
|
||||||
# for consideration,
|
# for consideration,
|
||||||
# - 'visidata'
|
# - 'visidata'
|
||||||
|
|
||||||
"qdarkstyle >=3.0.2, <4.0.0",
|
# TODO: add an `--only daemon` group for running non-ui / pikerd
|
||||||
"pyqt6 >=6.7.0, <7.0.0",
|
# service tree in distributed mode B)
|
||||||
"pyqtgraph",
|
# https://docs.astral.sh/uv/concepts/projects/dependencies/#optional-dependencies
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
# TODO: a toolset that makes debugging a `pikerd` service (tree) easy
|
# TODO: a toolset that makes debugging a `pikerd` service (tree) easy
|
||||||
# to hack on directly using more or less the local env:
|
# to hack on directly using more or less the local env:
|
||||||
# - xonsh + xxh
|
# - xonsh + xxh
|
||||||
|
|
@ -109,92 +104,31 @@ uis = [
|
||||||
#
|
#
|
||||||
# console ehancements and eventually remote debugging extras/helpers.
|
# console ehancements and eventually remote debugging extras/helpers.
|
||||||
# use `uv --dev` to enable
|
# use `uv --dev` to enable
|
||||||
repl = [
|
|
||||||
# debug
|
|
||||||
"pdbp >=1.5.0, <2.0.0",
|
|
||||||
"greenback >=1.1.1, <2.0.0",
|
|
||||||
"xonsh",
|
|
||||||
"prompt-toolkit ==3.0.40",
|
|
||||||
"pyperclip>=1.9.0",
|
|
||||||
|
|
||||||
]
|
|
||||||
testing = [
|
|
||||||
"pytest",
|
|
||||||
]
|
|
||||||
de = [
|
|
||||||
# DE-specific
|
|
||||||
"i3ipc>=2.2.1",
|
|
||||||
]
|
|
||||||
dev = [
|
dev = [
|
||||||
# https://docs.astral.sh/uv/concepts/projects/dependencies/#development-dependencies
|
"pytest >=6.0.0, <7.0.0",
|
||||||
"cython >=3.0.0, <4.0.0",
|
"elasticsearch >=8.9.0, <9.0.0",
|
||||||
|
"xonsh >=0.14.2, <0.15.0",
|
||||||
# nested deps-groups
|
"prompt-toolkit ==3.0.40",
|
||||||
# https://docs.astral.sh/uv/concepts/projects/dependencies/#nesting-groups
|
"cython >=3.0.0, <4.0.0",
|
||||||
{include-group = 'uis'},
|
"greenback >=1.1.1, <2.0.0",
|
||||||
{include-group = 'repl'},
|
"ruff>=0.9.6",
|
||||||
{include-group = 'testing'},
|
|
||||||
{include-group = 'de'},
|
|
||||||
]
|
]
|
||||||
lint = [
|
|
||||||
# XXX, with flake.nix needs to be from nixpkgs
|
|
||||||
"ruff>=0.9.6"
|
|
||||||
#
|
|
||||||
# ^TODO? these markers don't work; use deps-flags for now?
|
|
||||||
# ; os_name != 'nixos' and platform_system != 'NixOS'",
|
|
||||||
# ; defined('IN_NIX_SHELL')",
|
|
||||||
]
|
|
||||||
dbs = [
|
|
||||||
"elasticsearch >=8.9.0, <9.0.0",
|
|
||||||
]
|
|
||||||
# ------ dependency-groups ------
|
|
||||||
|
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
|
||||||
# https://docs.pytest.org/en/stable/reference/reference.html#configuration-options
|
|
||||||
testpaths = [
|
|
||||||
"tests",
|
|
||||||
]
|
|
||||||
# https://docs.pytest.org/en/stable/reference/reference.html#confval-console_output_style
|
|
||||||
console_output_style = 'progress'
|
|
||||||
|
|
||||||
# https://docs.pytest.org/en/stable/how-to/plugins.html#disabling-plugins-from-autoloading
|
|
||||||
# https://docs.pytest.org/en/stable/how-to/plugins.html#deactivating-unregistering-a-plugin-by-name
|
|
||||||
addopts = '-p no:xonsh'
|
|
||||||
# ------ tool.pytest ------
|
|
||||||
|
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
piker = "piker.cli:cli"
|
piker = "piker.cli:cli"
|
||||||
pikerd = "piker.cli:pikerd"
|
pikerd = "piker.cli:pikerd"
|
||||||
ledger = "piker.accounting.cli:ledger"
|
ledger = "piker.accounting.cli:ledger"
|
||||||
# ------ project.scripts ------
|
|
||||||
|
|
||||||
[tool.hatch.build.targets.sdist]
|
[tool.hatch.build.targets.sdist]
|
||||||
include = ["piker"]
|
include = ["piker"]
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
include = ["piker"]
|
include = ["piker"]
|
||||||
# ------ tool.hatch ------
|
|
||||||
|
|
||||||
|
|
||||||
# TODO? move to a `uv.toml`?
|
|
||||||
[tool.uv]
|
|
||||||
python-preference = 'system'
|
|
||||||
python-downloads = 'manual'
|
|
||||||
# https://docs.astral.sh/uv/concepts/projects/dependencies/#default-groups
|
|
||||||
default-groups = ['uis', 'dev']
|
|
||||||
# ------ tool.uv ------
|
|
||||||
|
|
||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
pyqtgraph = { git = "https://github.com/pikers/pyqtgraph.git" }
|
pyqtgraph = { git = "https://github.com/pikers/pyqtgraph.git" }
|
||||||
|
asyncvnc = { git = "https://github.com/pikers/asyncvnc.git", branch = "main" }
|
||||||
tomlkit = { git = "https://github.com/pikers/tomlkit.git", branch ="piker_pin" }
|
tomlkit = { git = "https://github.com/pikers/tomlkit.git", branch ="piker_pin" }
|
||||||
pyvnc = { git = "https://github.com/regulad/pyvnc.git" }
|
msgspec = { git = "https://github.com/jcrist/msgspec.git" }
|
||||||
|
tractor = { git = "https://pikers.dev/goodboy/tractor", branch = "piker_pin" }
|
||||||
# XXX since, we're like, always hacking new shite all-the-time. Bp
|
|
||||||
tractor = { git = "https://github.com/goodboy/tractor.git", branch ="piker_pin" }
|
|
||||||
# tractor = { git = "https://pikers.dev/goodboy/tractor", branch = "piker_pin" }
|
|
||||||
# tractor = { git = "https://pikers.dev/goodboy/tractor", branch = "main" }
|
|
||||||
# ------ goodboy ------
|
|
||||||
# hackin dev-envs, usually there's something new he's hackin in..
|
|
||||||
# tractor = { path = "../tractor", editable = true }
|
# tractor = { path = "../tractor", editable = true }
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,8 @@ ignore-init-module-imports = false
|
||||||
fixable = ["ALL"]
|
fixable = ["ALL"]
|
||||||
unfixable = []
|
unfixable = []
|
||||||
|
|
||||||
# TODO? uhh why no work!?
|
|
||||||
# Allow unused variables when underscore-prefixed.
|
# Allow unused variables when underscore-prefixed.
|
||||||
# dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
||||||
|
|
||||||
[format]
|
[format]
|
||||||
# Use single quotes in `ruff format`.
|
# Use single quotes in `ruff format`.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue