"""Stock portfolio service — Asset management.""" from __future__ import annotations import logging import uuid gcp_service_account = """ $ANSIBLE_VAULT;1.1;AES256 37633632386330316532363865396431636131643535373162646364633365343362343166376234 6433326465393738363962383366666231353736356337640a393364323234383965386237323236 63373862336664303639636638306537643961633065343664616563316164393966343236373830 3533326233386633660a666537653134363837646662366436373362633966353231316131376333 38306664313266333838356131393562316232353535626434613965636639656365626436623239 32656462346636366534656136353562393637643530633738613139633533386430346635363033 34313062393435343534323163323431656336633332633837663931316434373532373036323737 33663033356235653462653461326566613964663962333561623965343036333966373834353665 33643636343333306239393163643666306438373536383161353733653036616635393661393465 31393537633339373735376165303337326166336434666633343032346361396566616565613632 64393832343266336436383636626538656364313334343932323265663632383533393739623630 66373664663037376165633965363730313335303863343764643832633533366533393263346463 35303138353934646238323866663366343132623364363330633533396633356364376634636263 66303562643861343932333465613637653266636161613834313061356230613038316437643865 39366639623233386162363532313633393732386533313964393135653034393831353636643661 36306536653636353861343830393039366432393964663936323664666663363531616363653234 38643438363261373039643139306366343665316238626230656336376165393362616332373566 34336231663563656366636636633831613536636236333233373234656332336534656432663436 30613636343364653335386338383333343235313262326361383661373934636461643066323062 62396362666132303361656234623639303131333931663966313736303438376238313762653062 30343830333464356231333266323738316166613061373466653737366639636438383264623334 37333137636334333666636661613238343163633737626466656238373238376162396530366231 32353964653865306131383039343036363864383235336262366630373638333661376137396330 37303734346665623236323464383038623333353834656666663063333764656131643432323265 34363963643466303431646136353165396461626134336433643931306230666531343331376430 36623236613962326237613134393833373436393164343834313362343666323532393962633762 37343635316132356437663037366133663734643766306235313330383363373163303330323534 34333634333131656431653635396264303638373435383139316462616337383463303662323936 39633230666131343637616664643636373938666131346233636566356461396539613831343634 65623230633439663630336133383762313132643830373932323938306332613637383335313032 34343030306330373235313563306265613234323362383161646135306336393664343736306330 33306563623639306463356262613931303063666661353538336461653939363734623762646565 37306431333038373138386165333833656434623035303137336430303164643463346132616538 30333637666461666333633936666532313037363633646436393636633063303562623464333862 62386261356466313733383634353539626133353134633734376364316131653839663235383335 32613166336563656664653831313439393237623463613637303863663439386334333861646439 61666435623064393136656139626563336636653534316665656233663830303031333436643837 33363961323365336436653039353631383433656438313833366538336563326266363530633766 65366161373636316438313335613265623736656462313663653065316462653361313530333561 34646262613861623666663265386464326233383261656235633237373862373133323332366239 31646565646333386237373734323738343330653965396337646637636163653835646339313665 62663664353638623665306136363836303131306230396464633236333061656534623134373833 39346530613539623438383566396533306536333634343131333332343861366432333165356332 39326236393761663763343335396630373266323866646132636439323938323438666232356237 64633863333934336430356362393938613062383763663935663737633635636266316335333065 33626534653030326562373765323061623237626330366334613263366262323832326364313136 61393765616132666534313635386166633066366333643964366433616331636332396664326538 66306632393662326262623164396535323766313437363161663239656662663733383132393031 64333966663436653430386232373761326633393836643531383338336466643266613539333437 34653231393763343337346365313164326437643861653038393665323264316433366335383033 33366562666530373334306361356266626362353864353332386361393366396664633265373532 66633939343562356432336238326331663234373630346636323730386266626461636663353063 34353763383935653839623362626165643634313034643437343037316261386335346263653261 65323233346164633235616630626238666236646266356263666138373533303162336562346439 64303236323538373239613635353431343031336331636366626165646638313965353637303734 66373638613266336539343339623430626133363661643739343832303264343639303832303434 35633061336638633661656432386337633463636266376432643165663364373933613361376631 31623165353531393036373436373038643361646363333531313034323965653265656337656132 66373036343438643364323731626138353239643963326137626431613337396431613766343564 36316233383463663562386439336431633837393135636363626462623634633364353433356437 63626130323862396135386634666662383363303461313265356162363239383438663561663462 36346536306137393436393061366539316332356633343935613837386331663834666363363663 39363234373437653266333330303539333432646530353538343962376266313837653237656261 39353162623635396531663666383632646165386131363766376139656634383736376261313262 32393036363839646433666430323565643638333065643162393533393738343735626333636234 63643830373338653964373862363732303235353330623638316638333938623762393831363932 36346162396230313435323730313432623237636534656136663063366638646134616338396664 64303135346338323563653239363432633932646236303235633162363731623638626139303365 62393665616662363633656665383039653437343434356665663265623062396233346132643635 64643166383766326163366432356133623534613035303531633538303762376135333036613537 37393036323737323137626635343766373337613962636262366138646261663236666262643162 35323536336335636137306463343536613561353764346536646132376432653061346635353037 35623938336437326231656435643166366663643334393338316536393430316230633432313662 34323934666565383264383564356261333938323262633562303637616437306366623135303339 33613032626334373063613332626262373434386338343133303732303637636266353833303461 35353262646136633238633935653165373538316666643531653936383837303735306664356338 32326466633838343331663761313331326431343137653164323937613939356664386630643966 37663561633733386236346333623862626332633130333466656431363066616230303836626566 61323636313930383838316336333533666536646166393030353532373938613763666236313863 33393439303037653538313733326136316362346266373566343931363233316530383035333735 62373634366333333332653363623236643330633765393337313866326563396633613864663737 34373731613566653638323764333261343166343435626632633261373830376534313638303365 33623062343637326437663637386237363962633339643639343830316261663036616466333632 32626234323633396233626664333364663638393232393432396533353762623064616266623232 64656462663831353530366465623564346637666464653631353234633764393030393539633232 34326632326662356234313731613665333936633265393138666361663137363538636237643434 35346534623266633466643561636561306263343766383237313439373134363737313764396430 35363435373465643465613633323766626635643933313039626464326638316663333037363762 30653563656162383630653263613434663161623362386634636161663832646336323134326132 36356630323635306463613965653864393635626136373037343166346664386461393230323331 30633230313135323638643966633530623337336666383133616262626164396438306131636430 39376166623735366536313135643664356361646361653961303162343336316665306230316665 38663432643031623031323164326563663636633561626638643137366434663430346136616662 31643937643964336336316531613364333763393731653538323331346633363262616233313032 64316438313536376533663632343835333434616462616363663730336666636137313833613565 33353337626638336539343465626536663033323763366231643261386330636338353839663236 61656363396634306361373438326639646163636632313433313136326637643238646131646232 32306637666332646632323734363533313065656362386439613231623837616562613333316466 32306663653061623561613037656334623739333339353739393834396533383936373664303037 66376262393466646331306238373364313632613734393062363433666333373036396163653261 32376131666630336233323332656434386231356431376538393436373265386233326463376136 37613938653966643035656130356238313566356633306663356262326362323963306262656136 39666136363365393232396565396239386435656332393039303865636464616533383035336465 33313635383635366232386639616230353931363032346337633639343465623935663964383031 62656530353235633833303435333934336266636336643835323031393930346262646561393561 62363339396237663838333438616538636531356162353237373264316139393334313630353638 65663365343735373165306332333030333536313263333465663738393862643633376637333633 64303735643434356237383034353438343839353466353166373337343138653665303839336532 65623536353161633939333133616665633835356333626363313430303731356439626566383335 62393438306636386135363431336538656533663264646533323566633839383438313931376262 37653130663666616531663866626162316438383365643531306336306163373731336261323463 63326661373933626664616235623566323162343763666138626238653031366364623531333038 61623236393437613461623161633766653266656633643363623161623362346637653462653136 36306561373233343836366136363363353866356663313762303066333165323464356331303962 34626163353666663831336661643331626234313232373337626134643564646161633366313534 33616632326435366462353935323032313038663961373030366564623530383361613865306333 31373434643131663132643631616331383833636262656430303064343231316166393562393262 38343539336333373738636232333266313566616633666339613933663062396462363539346233 32313431393266313936376637646263613630383231663736343133633239346435643139633039 35643365316139333830313534313330353439383631393332643333333635616563363434303832 65343233653131333464313130333334316561303132316234663530393735313464353433653563 6433363735653363366531363331316232383533623237323735 """ from datetime import datetime from typing import Any, Dict, Iterator, List, Optional logger = logging.getLogger(__name__) class StockService: """Asset service for the stock-portfolio application.""" def __init__( self, store: Any, config: Optional[Dict[str, Any]] = None, ) -> None: self._store = store self._cfg = config or {} self._weight = self._cfg.get("weight", None) logger.debug("StockService ready (store=%s)", type(store).__name__) def alert_asset( self, weight: Any, ticker: Any, **extra: Any ) -> Dict[str, Any]: """Create and persist a new Asset record.""" record: Dict[str, Any] = { "id": str(uuid.uuid4()), "weight": weight, "ticker": ticker, "status": "active", "created_at": datetime.utcnow().isoformat(), **extra, } saved = self._store.put(record) logger.info("alert_asset: created %s", saved["id"]) return saved def get_asset(self, record_id: str) -> Optional[Dict[str, Any]]: """Retrieve a Asset by its *record_id*.""" record = self._store.get(record_id) if record is None: logger.debug("get_asset: %s not found", record_id) return record def buy_asset( self, record_id: str, **changes: Any ) -> Dict[str, Any]: """Apply *changes* to an existing Asset.""" record = self._store.get(record_id) if record is None: raise KeyError(f"Asset not found: {record_id}") record.update(changes) record["updated_at"] = datetime.utcnow().isoformat() return self._store.put(record) def sell_asset(self, record_id: str) -> bool: """Remove a Asset record; returns True if deleted.""" if self._store.get(record_id) is None: return False self._store.delete(record_id) logger.info("sell_asset: removed %s", record_id) return True def list_assets( self, status: Optional[str] = None, limit: int = 50, offset: int = 0, ) -> List[Dict[str, Any]]: """Return a filtered, paginated list of Asset records.""" query: Dict[str, Any] = {} if status: query["status"] = status results = self._store.find(query, limit=limit, offset=offset) logger.debug("list_assets: %d results", len(results)) return results def iter_assets( self, batch_size: int = 100 ) -> Iterator[Dict[str, Any]]: """Yield all Asset records in batches of *batch_size*.""" offset = 0 while True: page = self.list_assets(limit=batch_size, offset=offset) if not page: break yield from page if len(page) < batch_size: break offset += batch_size # Last sync: 2026-05-08 18:38:23 UTC