{"id":18255250,"url":"https://github.com/arklab/artesian.sdk-python","last_synced_at":"2025-10-05T23:06:35.920Z","repository":{"id":34883228,"uuid":"185778315","full_name":"ARKlab/Artesian.SDK-Python","owner":"ARKlab","description":"Python Library for Artesian","archived":false,"fork":false,"pushed_at":"2025-09-06T18:57:47.000Z","size":482,"stargazers_count":3,"open_issues_count":2,"forks_count":2,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-09-06T20:39:25.804Z","etag":null,"topics":["ark","artesian","energy-data","extraction","market-data","python","timeseries"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ARKlab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-05-09T10:30:44.000Z","updated_at":"2025-09-06T18:57:49.000Z","dependencies_parsed_at":"2023-01-15T09:54:31.511Z","dependency_job_id":"6b359ecb-5350-426b-b739-b6c404dbfad2","html_url":"https://github.com/ARKlab/Artesian.SDK-Python","commit_stats":{"total_commits":138,"total_committers":12,"mean_commits":11.5,"dds":0.5434782608695652,"last_synced_commit":"73639be84275f9bd76eb7cde800a25a3065e0a79"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/ARKlab/Artesian.SDK-Python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ARKlab%2FArtesian.SDK-Python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ARKlab%2FArtesian.SDK-Python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ARKlab%2FArtesian.SDK-Python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ARKlab%2FArtesian.SDK-Python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ARKlab","download_url":"https://codeload.github.com/ARKlab/Artesian.SDK-Python/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ARKlab%2FArtesian.SDK-Python/sbom","scorecard":{"id":7303,"data":{"date":"2025-08-11","repo":{"name":"github.com/ARKlab/Artesian.SDK-Python","commit":"0c936ab9f3ede50e1a34c76231e9142e24b8c75c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":6.3,"checks":[{"name":"Code-Review","score":10,"reason":"all changesets reviewed","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":5,"reason":"7 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: topLevel 'contents' permission set to 'read': .github/workflows/dependency-review.yaml:5","Warn: no topLevel permission defined: .github/workflows/python-tests.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dependency-review.yaml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/ARKlab/Artesian.SDK-Python/dependency-review.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dependency-review.yaml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/ARKlab/Artesian.SDK-Python/dependency-review.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-tests.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/ARKlab/Artesian.SDK-Python/python-tests.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-tests.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/ARKlab/Artesian.SDK-Python/python-tests.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/python-tests.yml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/ARKlab/Artesian.SDK-Python/python-tests.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-tests.yml:52: update your workflow using https://app.stepsecurity.io/secureworkflow/ARKlab/Artesian.SDK-Python/python-tests.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-tests.yml:67: update your workflow using https://app.stepsecurity.io/secureworkflow/ARKlab/Artesian.SDK-Python/python-tests.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-tests.yml:71: update your workflow using https://app.stepsecurity.io/secureworkflow/ARKlab/Artesian.SDK-Python/python-tests.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/python-tests.yml:82: update your workflow using https://app.stepsecurity.io/secureworkflow/ARKlab/Artesian.SDK-Python/python-tests.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/python-tests.yml:31","Warn: pipCommand not pinned by hash: .github/workflows/python-tests.yml:32","Warn: pipCommand not pinned by hash: .github/workflows/python-tests.yml:76","Warn: pipCommand not pinned by hash: .github/workflows/python-tests.yml:77","Info:   0 out of   7 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned","Info:   0 out of   4 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/python-tests.yml:59"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: all commits (30) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-14T13:50:12.858Z","repository_id":34883228,"created_at":"2025-08-14T13:50:12.858Z","updated_at":"2025-08-14T13:50:12.858Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278532352,"owners_count":26002346,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ark","artesian","energy-data","extraction","market-data","python","timeseries"],"created_at":"2024-11-05T10:15:16.221Z","updated_at":"2025-10-05T23:06:35.906Z","avatar_url":"https://github.com/ARKlab.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Artesian.SDK\n\nThis Library provides read access to the Artesian API\n\n## Getting Started\n\n### Installation\n\nYou can install the package directly from [pip](https://pypi.org/project/artesian-sdk/).\n\n```Python\npip install artesian-sdk\n```\n\nAlternatively, to install this package go to the [release page](https://github.com/ARKlab/Artesian.SDK-Python/releases) .\n\n### How to use\n\nThe Artesian.SDK instance can be configured using API-Key authentication\n\n```Python\nfrom Artesian import ArtesianConfig\n\ncfg = ArtesianConfig(\"https://arkive.artesian.cloud/{tenantName}/\", \"{api-key}\")\n```\n\n## BREAKING CHANGES: Upgrade v2-\u003ev3\n\nThe following breaking changes has been introduced in v3 respect to v2.\n\n### Python Version \u003e=3.8\n\nPython \u003e=3.8 is **required**.\nPython 3.7 is not supported due missing 'typing' features.\n\n### SubPackaging\n\nWith Artesian-SDK v3 we introduced SubPkg to split the different part of the library. The new SubPkg are:\n\n- Artesian.Query: contains all classes for querying Artesian data.\n- Artesian.GMEPublicOffers: contains all classes for querying GME Public Offers\n- **(NEW)** Artesian.MarketData: contains all classes to interact with the MarketData registry of Artesian. Register a new MarketData, change its Tags, etc. See documentation below.\n\nTo upgrade is enough to prefix the QueryService with 'Query.' or import it from Artesian.Query.\n\nWere was used:\n\n```Python\nfrom Artesian import *\n\ncfg = ArtesianConfig(\"https://arkive.artesian.cloud/{tenantName}/\", \"{api-key}\")\nqs = QueryService(cfg)\n```\n\nnow you have to:\n\n```Python\nfrom Artesian import ArtesianConfig\nfrom Artesian.Query import QueryService\n\ncfg = ArtesianConfig(\"https://arkive.artesian.cloud/{tenantName}/\", \"{api-key}\")\nqs = QueryService(cfg)\n```\n\n### Enum entries Casing\n\nTo align the casing of the entries of the Enum, we adopted PascalCase to align it with the Artesian API.\n\nWhere before was used\n\n```Python\n  .inGranularity(Granularity.HOUR) \\\n```\n\nnow is\n\n```Python\n  .inGranularity(Granularity.Hour) \\\n```\n\n## MarketData QueryService\n\nUsing the ArtesianConfig `cfg` we create an instance of the QueryService which is used to create Actual, Versioned and Market Assessment time series queries\n\n### Actual Time Series Extraction\n\n```Python\nfrom Artesian import ArtesianConfig, Granularity\nfrom Artesian.Query import QueryService, RelativeInterval\n\ncfg = ArtesianConfig(\"https://arkive.artesian.cloud/{tenantName}/\", \"{api-key}\")\n\nqs = QueryService(cfg)\ndata = qs.createActual() \\\n    .forMarketData([100011484,100011472,100011477,100011490,100011468,100011462,100011453]) \\\n    .inAbsoluteDateRange(\"2018-01-01\",\"2018-01-02\") \\\n    .inTimeZone(\"UTC\") \\\n    .inGranularity(Granularity.Hour) \\\n    .execute()\n\nprint(data)\n\n```\n\nTo construct an Actual Time Series Extraction the following must be provided.\n\n\u003ctable\u003e\n  \u003ctr\u003e\u003cth\u003eActual Query\u003c/th\u003e\u003cth\u003eDescription\u003c/th\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eMarket Data ID\u003c/td\u003e\u003ctd\u003eProvide a market data id or set of market data id's to query\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eTime Granularity\u003c/td\u003e\u003ctd\u003eSpecify the granularity type\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eTime Extraction Window\u003c/td\u003e\u003ctd\u003eAn extraction time window for data to be queried\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n[Go to Time Extraction window section](#artesian-sdk-extraction-windows)\n\n### Versioned Time Series Extraction\n\n```Python\nfrom Artesian import ArtesianConfig, Granularity\nfrom Artesian.Query import QueryService, RelativeInterval\n\nqs = QueryService(cfg)\nq = qs.createVersioned() \\\n    .forMarketData([100042422,100042283,100042285,100042281,100042287,100042291,100042289]) \\\n    .inAbsoluteDateRange(\"2018-01-01\",\"2018-01-02\") \\\n    .inTimeZone(\"UTC\") \\\n    .inGranularity(Granularity.Hour)\n\nprint(q)\n\nret = q.forMUV().execute()\nprint(ret)\nret = q.forLastNVersions(2).execute()\nprint(ret)\nret = q.forLastOfDays(\"2019-03-12\",\"2019-03-16\").execute()\nprint(ret)\nret = q.forLastOfDays(\"P0Y0M-2D\",\"P0Y0M2D\").execute()\nprint(ret)\nret = q.forLastOfDays(\"P0Y0M-2D\").execute()\nprint(ret)\nret = q.forLastOfMonths(\"2019-03-12\",\"2019-03-16\").execute()\nprint(ret)\nret = q.forLastOfMonths(\"P0Y-1M0D\",\"P0Y1M0D\").execute()\nprint(ret)\nret = q.forLastOfMonths(\"P0Y-1M0D\").execute()\nprint(ret)\nret = q.forVersion(\"2019-03-12T14:30:00\").execute()\nprint(ret)\nret = q.forMostRecent(\"2019-03-12\",\"2019-03-16\").execute()\nprint(ret)\nret = q.forMostRecent(\"2019-03-12T12:30:05\",\"2019-03-16T18:42:30\").execute()\nprint(ret)\nret = q.forMostRecent(\"P0Y0M-2D\",\"P0Y0M2D\").execute()\nprint(ret)\nret = q.forMostRecent(\"P0Y0M-2D\").execute()\nprint(ret)\nret = q.forMostRecent(\"2019-03-12\",\"2019-03-16\").execute()\nprint(ret)\nret = q.forMostRecent(\"P0Y-1M0D\",\"P0Y1M0D\").execute()\nprint(ret)\nret = q.forMostRecent(\"P0Y-1M0D\").execute()\nprint(ret)\n```\n\nTo construct a Versioned Time Series Extraction the following must be provided.\n\n\u003ctable\u003e\n  \u003ctr\u003e\u003cth\u003eVersioned Query\u003c/th\u003e\u003cth\u003eDescription\u003c/th\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eMarket Data ID\u003c/td\u003e\u003ctd\u003eProvide a market data id or set of market data id's to query\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eTime Granularity\u003c/td\u003e\u003ctd\u003eSpecify the granularity type\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eVersioned Time Extraction Window\u003c/td\u003e\u003ctd\u003eVersioned extraction time window\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eTime Extraction Window\u003c/td\u003e\u003ctd\u003eAn extraction time window for data to be queried\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n[Go to Time Extraction window section](#artesian-sdk-extraction-windows)\n\n### Market Assessment Time Series Extraction\n\n```Python\nfrom Artesian import ArtesianConfig\nfrom Artesian.Query import QueryService, RelativeInterval\n\nqs = QueryService(cfg)\ndata = qs.createMarketAssessment() \\\n    .forMarketData([100000032,100000043]) \\\n    .forProducts([\"D+1\",\"Feb-18\"]) \\\n    .inAbsoluteDateRange(\"2018-01-01\",\"2018-01-02\") \\\n    .execute()\n\nprint(data)\n```\n\nTo construct a Market Assessment Time Series Extraction the following must be provided.\n\n\u003ctable\u003e\n  \u003ctr\u003e\u003cth\u003eMas Query\u003c/th\u003e\u003cth\u003eDescription\u003c/th\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eMarket Data ID\u003c/td\u003e\u003ctd\u003eProvide a market data id or set of market data id's to query\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eProduct\u003c/td\u003e\u003ctd\u003eProvide a product or set of products\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eTime Extraction Window\u003c/td\u003e\u003ctd\u003eAn extraction time window for data to be queried \u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n[Go to Time Extraction window section](#artesian-sdk-extraction-windows)\n\n### Bid Ask Time Series Extraction\n\n```Python\nfrom Artesian import ArtesianConfig\nfrom Artesian.Query import QueryService, RelativeInterval\n\nqs = QueryService(cfg)\ndata = qs.createBidAsk() \\\n    .forMarketData([100000032,100000043]) \\\n    .forProducts([\"D+1\",\"Feb-18\"]) \\\n    .inAbsoluteDateRange(\"2018-01-01\",\"2018-01-02\") \\\n    .execute()\n\nprint(data)\n```\n\nTo construct a Bid Ask Time Series Extraction the following must be provided.\n\n\u003ctable\u003e\n  \u003ctr\u003e\u003cth\u003eMas Query\u003c/th\u003e\u003cth\u003eDescription\u003c/th\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eMarket Data ID\u003c/td\u003e\u003ctd\u003eProvide a market data id or set of market data id's to query\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eProduct\u003c/td\u003e\u003ctd\u003eProvide a product or set of products\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eTime Extraction Window\u003c/td\u003e\u003ctd\u003eAn extraction time window for data to be queried \u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n[Go to Time Extraction window section](#artesian-sdk-extraction-windows)\n\n### Auction Time Series Extraction\n\n```Python\nfrom Artesian import ArtesianConfig\nfrom Artesian.Query import QueryService, RelativeInterval\n\nqs = QueryService(cfg)\ndata = qs.createAuction() \\\n    .forMarketData([100011484,100011472,100011477,100011490,100011468,100011462,100011453]) \\\n    .inAbsoluteDateRange(\"2018-01-01\",\"2018-01-02\") \\\n    .inTimeZone(\"UTC\") \\\n    .execute()\n\nprint(data)\n```\n\nTo construct an Auction Time Series Extraction the following must be provided.\n\n\u003ctable\u003e\n  \u003ctr\u003e\u003cth\u003eAuction Query\u003c/th\u003e\u003cth\u003eDescription\u003c/th\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eMarket Data ID\u003c/td\u003e\u003ctd\u003eProvide a market data id or set of market data id's to query\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eTime Extraction Window\u003c/td\u003e\u003ctd\u003eAn extraction time window for data to be queried\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n[Go to Time Extraction window section](#artesian-sdk-extraction-windows)\n\n### Extraction Windows\n\nExtraction window types for queries.\n\nDate Range\n\n```Python\n .inAbsoluteDateRange(\"2018-08-01\", \"2018-08-10\")\n```\n\nRelative Interval\n\n```Python\n .inRelativeInterval(RelativeInterval.RollingWeek)\n```\n\nPeriod\n\n```Python\n .inRelativePeriod(\"P5D\")\n```\n\nPeriod Range\n\n```Python\n .inRelativePeriodRange(\"P-3D\", \"P10D\")\n```\n\n### Filler Strategy\n\nAll extraction types (Actual,Versioned, Market Assessment and BidAsk) have an optional filler strategy.\n\n```python\nvar versionedSeries = qs\n  .createVersioned() \\\n  .forMarketData([100000001]) \\\n  .forLastNVersions(1) \\\n  .inGranularity(Granularity.Day) \\\n  .inAbsoluteDateRange(new Date(\"2018-1-1\"), new Date(\"2018-1-10\")) \\\n  .withFillLatestValue(\"P5D\") \\\n  .execute()\n```\n\nUse 'Null' to fill the missing timepoint with 'None' values.\n\n```python\n .withFillNull()\n```\n\nUse 'None' to not fill at all: timepoints are not returned if not present.\n\n```python\n .withFillNone()\n```\n\nCustom Value can be provided for each MarketDataType.\n\nCustom Value for Actual extraction type.\n\n```python\n.withFillCustomValue(123)\n```\n\nCustom Value for BidAsk extraction type.\n\n```python\n.withFillCustomValue(\n  bestBidPrice = 15.0,\n  bestAskPrice = 20.0,\n  bestBidQuantity = 30.0,\n  bestAskQuantity = 40.0,\n  lastPrice = 50.0,\n  lastQuantity = 60.0)\n```\n\nCustom Value for Market Assessment extraction type.\n\n```python\n.withFillCustomValue(\nsettlement = 10.0,\nopen = 20.0,\nclose = 30.0,\nhigh = 40.0,\nlow = 50.0,\nvolumePaid = 60.0,\nvolueGiven = 70.0,\nvolume = 80.0)\n```\n\nCustom Value for Versioned extraction type.\n\n```python\n.withFillCustomValue(123)\n```\n\nLatest Value to propagate the latest value, not older than a certain threshold only if there is a value at the end of the period.\n\n```python\n .withFillLatestValue(\"P5D\")\n```\n\n```python\n .withFillLatestValue(\"P5D\", \"False\")\n```\n\nLatest Value to propagate the latest value, not older than a certain threshold even if there's no value at the end.\n\n```python\n .withFillLatestValue(\"P5D\", \"True\")\n```\n\n### Query written Versions or Products\n\nUsing MarketDataService is possible to query all the Versions and all the Products curves which has been written in a MarketData.\n\n```Python\nfrom Artesian.MarketData import MarketDataService\n\nmds = MarketDataService(cfg)\n\n```\n\nTo list MarketData curves\n\n```Python\npage = 1\npageSize = 100\nres = mds.readCurveRange(100042422, page, pageSize, versionFrom=\"2016-12-20\" , versionTo=\"2019-03-12\")\n```\n\n### Search the MarketData collection with faceted results\n\nUsing MarketDataService is possible to query and search the MarketData collection with faceted results. Supports paging, filtering and free text.\n\n```Python\nfrom Artesian.MarketData import MarketDataService\n\nmds = MarketDataService(cfg)\n\n```\n\nTo list MarketData curves\n\n```Python\npage = 1\npageSize = 100\nsearchText = \"Riconsegnato_\"\nfilters = {\"ProviderName\": [\"SNAM\", \"France\"]}\nsorts=[\"MarketDataId asc\"]\ndoNotLoadAdditionalInfo=True\nres = mds.searchFacet(page, pageSize, searchText, filters, sorts, doNotLoadAdditionalInfo)\n```\n\n## GME Public Offer\n\nArtesian support Query over GME Public Offers which comes in a custom and dedicated format.\n\n### Extract GME Public Offer\n\n```Python\nfrom Artesian.GMEPublicOffers import GMEPublicOfferService, Market, Purpose, Status, Zone, Scope, UnitType, GenerationType, BAType\n\nqs = GMEPublicOfferService(cfg)\n\ndata = qs.createQuery() \\\n    .forDate(\"2020-04-01\") \\\n    .forMarket([Market.MGP]) \\\n    .forStatus(Status.ACC) \\\n    .forPurpose(Purpose.BID) \\\n    .forZone([Zone.NORD]) \\\n    .withPagination(1,100) \\\n    .execute()\n\nprint(data)\n```\n\nTo construct a GME Public Offer Extraction the following must be provided.\n\n\u003ctable\u003e\n  \u003ctr\u003e\u003cth\u003eGME Public Offer Query\u003c/th\u003e\u003cth\u003eDescription\u003c/th\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eTime Extraction Window\u003c/td\u003e\u003ctd\u003eAn extraction time window for data to be queried\u003c/td\u003e\u003c/tr\u003e\n  \u003ctr\u003e\u003ctd\u003eMarket\u003c/td\u003e\u003ctd\u003eProvide a market or set of markets to query\u003c/td\u003e\u003c/tr\u003e\n   \u003ctr\u003e\u003ctd\u003eStatus\u003c/td\u003e\u003ctd\u003eProvide a status or set of statuses to query\u003c/td\u003e\u003c/tr\u003e\n    \u003ctr\u003e\u003ctd\u003ePurpose\u003c/td\u003e\u003ctd\u003eProvide a purpose or set of purposes to query\u003c/td\u003e\u003c/tr\u003e\n     \u003ctr\u003e\u003ctd\u003eZone\u003c/td\u003e\u003ctd\u003eProvide a zone to query\u003c/td\u003e\u003c/tr\u003e\n     \n\u003c/table\u003e\n\n### Unit of Measure Conversion Functionality\n\n### Overview\n\nThe unit of measure conversion functionality allows users to request a conversion of units for Market Data that was registered using a different unit. This feature is supported only for Actual and Versioned Time Series.\nSupported units are defined in the CommonUnitOfMeasure object and conform to ISO/IEC 80000 (i.e., `kW`, `MW`, `kWh`, `MWh`, `m`, `km`, `day`, `min`, `h`, `s`, `mo`, `yr`).\n\nNote: Duration-based units are interpreted with the following fixed assumptions:\n`1 day = 24 hours`\n`1 mo = 30 days`\n`1 yr = 365 days`\n\nAdditional supported units include **currency codes** in 3-letter format as per ISO 4217:2015 (e.g., `EUR`, `USD`, `JPY`). These are not part of CommonUnitOfMeasure and must be specified as regular strings.\nUnits of measure can also be **composite**, using the {a}/{b} syntax, where both {a} and {b} are either units from CommonUnitOfMeasure or ISO 4217 currency codes.\n\n### Conversion Logic\n\nUnit conversion is based on the assumption that each unit of measure can be decomposed into a **\"BaseDimension\"**, which represents a polynomial of base SI units (`m`, `s`, `kg`, etc.) and currencies (`EUR`, `USD`, etc.).\nA unit of measure is represented as a value in BaseDimension UnitOdMeasure.\nExample:\n10 `Wh` = 10 `kg·m²·s⁻³`\nConversion is allowed when the BaseDimensions **match exactly**, i.e., the same set of base units raised to the same exponents.\nIn Artesian, units that differ **only** in the **time dimension** are also potentially convertible, as the time dimension can be inferred from the data’s time interval.\n\n### Example: Power to Energy Conversion\n\nConverting `W` to `Wh`:\n• `W` → BaseDimension: `k·m²·s⁻³`\n• `Wh` → BaseDimension: `kg·m²·s⁻²`\n• `1 h = 3600 s`\n**Conversion Steps:**\n10 W = 10 kg·m²/s³\n1 h = 3600 s\n10 kg·m²/s³ × 3600 s = 36000 kg·m²/s² = 10 Wh\n\n### MarketData Registration with UnitOfMeasure\n\nThe UnitOfMeasure is defined during registration:\n\n```Python\nmkd = MarketData.MarketDataEntityInput(\n      providerName = \"TestProviderName\",\n      marketDataName = \"TestMarketDataName\",\n      originalGranularity=Granularity.Day,\n      type=MarketData.MarketDataType.ActualTimeSerie,\n      originalTimezone=\"CET\",\n      aggregationRule=AggregationRule.SumAndDivide,\n    UnitOfMeasure = CommonUnitOfMeasure.kW\n  )\n\nregistered = mkservice.readMarketDataRegistryByName(mkdid.provider, mkdid.name)\nif (registered is None):\n  registered = mkservice.registerMarketData(mkd)\n```\n\n### UnitOfMeasure Conversion and Aggregation Rule Override\n\nIn the QueryService, there are two supported methods related to unit of measure handling during extraction:\n\n1. UnitOfMeasure Conversion\n2. Aggregation Rule Override\n\n### UnitOfMeasure Conversion\n\nTo convert a UnitOfMeasure during data extraction, use the `.inUnitOfMeasure()` method. This function converts the data from the unit defined at MarketData registration to the target unit you specify in the query.\n\n```Python\nqs = QueryService(cfg)\ndata = qs.createActual() \\\n    .forMarketData([100011484]) \\\n    .inAbsoluteDateRange(\"2024-01-01\",\"2024-01-02\") \\\n    .inTimeZone(\"UTC\") \\\n    .inGranularity(Granularity.Day) \\\n    .inUnitOfMeasure(CommonUnitOfMeasure.MW) \\\n    .execute()\n```\n\nBy default, the aggregation rule used during extraction is the one defined at registration. However, you can override it if needed. The conversion is always applied before aggregation.\n\n### Aggregation Rule Override\n\nAggregationRule can be overrided using the `.withAggregationRule()` method in QueryService.\n\n```Python\nqs = QueryService(cfg)\ndata = qs.createActual() \\\n    .forMarketData([100011484]) \\\n    .inAbsoluteDateRange(\"2024-01-01\",\"2024-01-02\") \\\n    .inTimeZone(\"UTC\") \\\n    .inGranularity(Granularity.Day) \\\n    .withAggregationRule(AggregationRule.AverageAndReplicate) \\\n    .execute()\n```\n\nSometimes, especially when converting from a **consumption unit** (e.g., `MWh`) to a **power unit** (e.g., `MW`), the registered aggregation rule (e.g., `SumAndDivide`) may not make sense for the new unit.\n\nIf you **don’t override the aggregation rule**, the conversion may produce **invalid or misleading results**.\n\n### Example: Convert power (`MW`) to energy (`MWh`):\n\n```Python\ndata = qs.createActual() \\\n    .forMarketData([100011484]) \\\n    .inAbsoluteDateRange(\"2024-01-01\",\"2024-01-02\") \\\n    .inTimeZone(\"UTC\") \\\n    .inGranularity(Granularity.Day) \\\n    .inUnitOfMeasure(CommonUnitOfMeasure.MWh) \\\n    .withAggregationRule(AggregationRule.AverageAndReplicate) \\\n    .execute()\n```\n\n### Composite Unit Example: `MWh/day`\n\n```Python\ndata = qs.createActual() \\\n    .forMarketData([100011484]) \\\n    .inAbsoluteDateRange(\"2024-01-01\",\"2024-01-02\") \\\n    .inTimeZone(\"UTC\") \\\n    .inGranularity(Granularity.Day) \\\n    .inUnitOfMeasure(CommonUnitOfMeasure.MWh / CommonUnitOfMeasure.day) \\\n    .withAggregationRule(AggregationRule.AverageAndReplicate) \\\n    .execute()\n```\n\n### CheckConversion: Validate Unit Compatibility\n\nUse the `CheckConversion` method to verify whether a list of input units can be converted into a specifified target unit:\n\n```Python\nfrom Artesian import ArtesianConfig, MarketData\nfrom Artesian.MarketData import CommonUnitOfMeasure\n\ncfg = ArtesianConfg()\n\nmkservice = MarketData.MarketDataService(cfg)\n\ninputUnitsOfMeasure = [CommonUnitOfMeasure.kW, CommonUnitOfMeasure.kWh, \"EUR/MWh\"]\ntargetUnitOfMeasure = CommonUnitOfMeasure.MW\n\ncheckConversionResult = mkservice.checkConversion(inputUnitsOfMeasure , targetUnitOfMeasure)\n```\n\n**Returned Object: CheckConversionResult**\n\n1. TargetUnitOfMeasure: \"`kW`\"\n2. ConvertibleInputUnitsOfMeasure: [ \"`MW`\", \"`kW/s`\" ]\n3. NotConvertibleInputUnitsOfMeasure: [ \"`s`\" ]\n\n### Extraction Options\n\nExtraction options for GME Public Offer queries.\n\n#### Date\n\n```Python\n .forDate(\"2020-04-01\")\n```\n\n#### Purpose\n\n```Python\n .forPurpose(Purpose.BID)\n```\n\n#### Status\n\n```Python\n .forStatus(Status.ACC)\n```\n\n#### Operator\n\n```Python\n .forOperator([\"Operator_1\", \"Operator_2\"])\n```\n\n#### Unit\n\n```Python\n .forUnit([\"UP_1\", \"UP_2\"])\n```\n\n#### Market\n\n```Python\n .forMarket([Market.MGP])\n```\n\n#### Scope\n\n```Python\n .forScope([Scope.ACC, Scope.RS])\n```\n\n#### BAType\n\n```Python\n .forBAType([BAType.NETT, BAType.NERV])\n```\n\n#### Zone\n\n```Python\n .forZone([Zone.NORD])\n```\n\n#### UnitType\n\n```Python\n .forUnitType([UnitType.UCV, UnitType.UPV])\n```\n\n#### Generation Type\n\n```Python\n .forGenerationType(GenerationType.GAS)\n```\n\n#### Pagination\n\n```Python\n .withPagination(1,10)\n```\n\n#### UnitOfMeasure (for Actual and Versioned Time Series)\n\n```Python\n .inUnitOfMeasure(CommonUnitOfMeasure.kWh)\n```\n\n#### AggregationRule (for Actual and Versioned Time Series)\n\n```Python\n .withAggregationRule(AggregationRule.SumAndDivide)\n```\n\n## Write Data in Artesian\n\nUsing the MarketDataService is possible to register MarketData and write curves into it using the UpsertData method.\n\nDepending on the Type of the MarketData, the UpsertData should be composed as per example below.\n\n### Write Data in an Actual Time Series\n\n```Python\nfrom Artesian import ArtesianConfig, Granularity, MarketData\nfrom Artesian.MarketData import AggregationRule\nfrom datetime import datetime\nfrom dateutil import tz\n\ncfg = ArtesianConfg()\n\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\nmkd = MarketData.MarketDataEntityInput(\n      providerName = mkdid.provider,\n      marketDataName = mkdid.name,\n      originalGranularity=Granularity.Day,\n      type=MarketData.MarketDataType.ActualTimeSerie,\n      originalTimezone=\"CET\",\n      aggregationRule=AggregationRule.AverageAndReplicate,\n      tags={\n        'TestSDKPython': ['PythonValue2']\n      },\n      derivedCfg=DerivedCfg(\n                version=1,\n                derivedAlgorithm=DerivedAlgorithm.Coalesce,\n                orderedReferencedMarketDataIds=[10000, 10001, 10002],\n            ),\n  )\n\nregistered = mkservice.readMarketDataRegistryByName(mkdid.provider, mkdid.name)\nif (registered is None):\n  registered = mkservice.registerMarketData(mkd)\n\ndata = MarketData.UpsertData(mkdid, 'CET',\n  rows=\n  {\n      datetime(2020,1,1): 42.0,\n      datetime(2020,1,2): 43.0,\n  },\n  downloadedAt=datetime(2020,1,3).replace(tzinfo=tz.UTC)\n  )\n\nmkservice.upsertData(data)\n```\n\nUpsert has optional switches that can be applied\n```\nmkservice.upsertData(data, deferCommandExecution, deferDataGeneration, keepNulls, upsertMode)\n```\nThe switch details are,\n\ndeferCommandExecution (true/false) choose between syncronoys and asyncronous command execution, default is false.\ndeferDataGeneration (true/false) choose between syncronoys and asyncronous precomputed data generation, default is true.\nkeepNulls (true/false) if true then nulls are written in the curve replacing any data present for the instant, default is false.\nupsertMode (Merge/Replace) for ActualTimeSeries the two modes are equivalent. Leaving Null/None/Empty is equivalent to Merge.\n\n\nDerivedCfg can be of algorithm type: Coalesce, Sum, Muv.\n\nUpdating the DerivedCfg can be performed with `updateDerivedConfiguration` on MarketDataService. A validation will be done on the existing DerivedCfg of the MarketData, that should be not null and with same type as the one used for the update.\n\n```csharp\nderivedCfgUpdate = DerivedCfg(\n    version=1,\n    derivedAlgorithm=DerivedAlgorithm.Coalesce,\n    orderedReferencedMarketDataIds=[10002, 10001, 10000],\n)\n\nmarketDataUpdated = mkdservice.updateDerivedConfiguration(\n                        registeredDerived.marketDataId,\n                        derivedCfgUpdate,\n                        False)\n```\n\nIn case we want to write an hourly (or lower) time series the timezone for the upsert data must be UTC:\n\n```Python\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\nmkd = MarketData.MarketDataEntityInput(\n      providerName = mkdid.provider,\n      marketDataName = mkdid.name,\n      originalGranularity=Granularity.Hour,\n      type=MarketData.MarketDataType.ActualTimeSerie,\n      originalTimezone=\"CET\",\n      aggregationRule=AggregationRule.AverageAndReplicate,\n      tags={\n        'TestSDKPython': ['PythonValue2']\n      }\n  )\n\nregistered = mkservice.readMarketDataRegistryByName(mkdid.provider, mkdid.name)\nif (registered is None):\n  registered = mkservice.registerMarketData(mkd)\n\ndata = MarketData.UpsertData(mkdid, 'UTC',\n  rows=\n  {\n      datetime(2020,1,1,5,0,0): 42.0,\n      datetime(2020,1,2,6,0,0): 43.0,\n      datetime(2020,1,2,7,0,0): 44.0,\n      datetime(2020,1,2,8,0,0): 45.0,\n      datetime(2020,1,2,9,0,0): 46.0,\n  },\n  downloadedAt=datetime(2020,1,3).replace(tzinfo=tz.UTC)\n  )\n\nmkservice.upsertData(data)\n\n```\n\n### Write Data in a Versioned Time Series\n\n```Python\nfrom Artesian import ArtesianConfig, Granularity, MarketData\nfrom Artesian.MarketData import AggregationRule\nfrom datetime import datetime\nfrom dateutil import tz\n\ncfg = ArtesianConfg()\n\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\nmkd = MarketData.MarketDataEntityInput(\n      providerName = mkdid.provider,\n      marketDataName = mkdid.name,\n      originalGranularity=Granularity.Day,\n      type=MarketData.MarketDataType.VersionedTimeSerie,\n      originalTimezone=\"CET\",\n      aggregationRule=AggregationRule.AverageAndReplicate,\n      tags={\n        'TestSDKPython': ['PythonValue2']\n      }\n  )\n\nregistered = mkservice.readMarketDataRegistryByName(mkdid.provider, mkdid.name)\nif (registered is None):\n  registered = mkservice.registerMarketData(mkd)\n\ndata = MarketData.UpsertData(mkdid, 'CET',\n  rows=\n  {\n      datetime(2020,1,1): 42.0,\n      datetime(2020,1,2): 43.0,\n  },\n  version= datetime(2020,1,3,12,0),\n  downloadedAt=datetime(2020,1,3).replace(tzinfo=tz.UTC)\n  )\n\nmkservice.upsertData(data)\n\n```\n\nUpsert has optional switches that can be applied\n```\nmkservice.upsertData(data, deferCommandExecution, deferDataGeneration, keepNulls, upsertMode)\n```\nThe switch details are,\n\ndeferCommandExecution (true/false) choose between syncronoys and asyncronous command execution, default is false.\ndeferDataGeneration (true/false) choose between syncronoys and asyncronous precomputed data generation, default is true.\nkeepNulls (true/false) if true then nulls are written in the curve replacing any data present for the instant, default is false.\nupsertMode (Merge/Replace) for VersionedTimeSeries the merge writes in to the curve replacing existing data for an existing instant, replace writes the payload removing any previous data for the version. Leaving Null/None/Empty is equivalent to Merge.\n\n| DATETIME | EXISTING | PAYLOAD | MERGE | REPALACE |\n|---|---|---|---|---|\n| VERSION NAME | 2025-01-01 | 2025-01-01 | 2025-01-01 | 2025-01-01 |\n| 2025-01-01 |        |        |        |        |\n| 2025-01-02 | 999.99 | 222.22 | 222.22 | 222.22 |\n| 2025-01-03 | 999.99 | 222.22 | 222.22 | 222.22 |\n| 2025-01-04 | 999.99 | 222.22 | 222.22 | 222.22 |\n| 2025-01-05 | 999.99 | 222.22 | 222.22 | 222.22 |\n| 2025-01-06 | 999.99 | 222.22 | 222.22 | 222.22 |\n| 2025-01-07 | 999.99 | 222.22 | 222.22 | 222.22 |\n| 2025-01-08 |        | 222.22 | 222.22 | 222.22 |\n| 2025-01-09 |        |        |        |        |\n| 2025-01-10 |        |        |        |        |\n| 2025-01-11 | 999.99 |        | 999.99 |        |\n| 2025-01-12 | 999.99 |        | 999.99 |        |\n| 2025-01-13 | 999.99 |        | 999.99 |        |\n| 2025-01-14 |        |        |        |        |\n| 2025-01-15 |        |        |        |        |\n\n\n### Write Data in a Market Assessment Time Series\n\n```Python\nfrom Artesian import ArtesianConfig, Granularity, MarketData\nfrom datetime import datetime\nfrom dateutil import tz\n\ncfg = ArtesianConfg()\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\nmkd = MarketData.MarketDataEntityInput(\n      providerName = mkdid.provider,\n      marketDataName = mkdid.name,\n      originalGranularity=Granularity.Day,\n      type=MarketData.MarketDataType.MarketAssessment,\n      originalTimezone=\"CET\",\n      tags={\n        'TestSDKPython': ['PythonValue2']\n      }\n  )\n\nregistered = mkservice.readMarketDataRegistryByName(mkdid.provider, mkdid.name)\nif (registered is None):\n  registered = mkservice.registerMarketData(mkd)\n\nmarketAssessment = MarketData.UpsertData(MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME'), 'CET',\n  marketAssessment=\n  {\n      datetime(2020,1,1):\n      {\n         \"Feb-20\": MarketData.MarketAssessmentValue(open=10.0, close=11.0),\n         \"Mar-20\": MarketData.MarketAssessmentValue(open=20.0, close=21.0)\n      },\n          datetime(2020,1,2):\n          {\n              \"Feb-20\": MarketData.MarketAssessmentValue(open=11.0, close=12.0),\n              \"Mar-20\": MarketData.MarketAssessmentValue(open=21.0, close=22.0)\n          }\n  },\n  downloadedAt=datetime(2020,1,3).replace(tzinfo=tz.UTC)\n  )\n\nmkservice.upsertData(marketAssessment)\n\n```\n\nUpsert has optional switches that can be applied\n```\nmkservice.upsertData(data, deferCommandExecution, deferDataGeneration, keepNulls, upsertMode)\n```\nThe switch details are,\n\ndeferCommandExecution (true/false) choose between syncronoys and asyncronous command execution, default is false.\ndeferDataGeneration (true/false) choose between syncronoys and asyncronous precomputed data generation, default is true.\nkeepNulls (true/false) if true then nulls are written in the curve replacing any data present for the instant, default is false.\nupsertMode (Merge/Replace) for MarketAssessment merge adds the new products to the existing and overwrites existing with the new ones while replace replaces all the existing products with the new ones. Leaving Null/None/Empty is equivalent to Merge.\n\n\n### Write Data in a Bid Ask Time Series\n\n```Python\nfrom Artesian import ArtesianConfig,Granularity,MarketData\nfrom datetime import datetime\nfrom dateutil import tz\n\ncfg = ArtesianConfg()\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\nmkd = MarketData.MarketDataEntityInput(\n      providerName = mkdid.provider,\n      marketDataName = mkdid.name,\n      originalGranularity=Granularity.Day,\n      type=MarketData.MarketDataType.BidAsk,\n      originalTimezone=\"CET\",\n      tags={\n        'TestSDKPython': ['PythonValue2']\n      }\n  )\n\nregistered = mkservice.readMarketDataRegistryByName(mkdid.provider, mkdid.name)\nif (registered is None):\n  registered = mkservice.registerMarketData(mkd)\n\nbidAsk = MarketData.UpsertData(MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME'), 'CET',\n  bidAsk={\n      datetime(2020,1,1):\n      {\n          \"Feb-20\":MarketData.BidAskValue(bestBidPrice=15.0, lastQuantity=14.0),\n          \"Mar-20\":MarketData.BidAskValue(bestBidPrice=25.0, lastQuantity=24.0)\n      },\n      datetime(2020,1,2):\n      {\n          \"Feb-20\":MarketData.BidAskValue(bestBidPrice=15.0, lastQuantity=14.0),\n          \"Mar-20\":MarketData.BidAskValue(bestBidPrice=25.0, lastQuantity=24.0)\n      }\n\n  },\n  downloadedAt=datetime(2020,1,3).replace(tzinfo=tz.UTC)\n  )\n\nmkservice.upsertData(bidAsk)\n```\n\nUpsert has optional switches that can be applied\n```\nmkservice.upsertData(data, deferCommandExecution, deferDataGeneration, keepNulls, upsertMode)\n```\nThe switch details are,\n\ndeferCommandExecution (true/false) choose between syncronoys and asyncronous command execution, default is false.\ndeferDataGeneration (true/false) choose between syncronoys and asyncronous precomputed data generation, default is true.\nkeepNulls (true/false) if true then nulls are written in the curve replacing any data present for the instant, default is false.\nupsertMode (Merge/Replace) for BidAsk merge adds the new products to the existing and overwrites existing with the new ones while replace replaces all the existing products with the new ones. Leaving Null/None/Empty is equivalent to Merge.\n\n\n### Write Data in an Auction Time Series\n\n```Python\nfrom Artesian import ArtesianConfig,Granularity,MarketData\nfrom datetime import datetime\nfrom dateutil import tz\n\ncfg = ArtesianConfg()\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\nmkd = MarketData.MarketDataEntityInput(\n      providerName = mkdid.provider,\n      marketDataName = mkdid.name,\n      originalGranularity=Granularity.Day,\n      type=MarketData.MarketDataType.Auction,\n      originalTimezone=\"CET\",\n      tags={\n        'TestSDKPython': ['PythonValue2']\n      }\n  )\n\nregistered = mkservice.readMarketDataRegistryByName(mkdid.provider, mkdid.name)\nif (registered is None):\n  registered = mkservice.registerMarketData(mkd)\n\nauctionRows = MarketData.UpsertData(MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME'), 'CET',\n  auctionRows={\n      datetime(2020,1,1): MarketData.AuctionBids(datetime(2020,1,1),\n          bid=[\n              MarketData.AuctionBidValue(11.0, 12.0),\n              MarketData.AuctionBidValue(13.0, 14.0),\n          ],\n          offer=[\n              MarketData.AuctionBidValue(21.0, 22.0),\n              MarketData.AuctionBidValue(23.0, 24.0),\n          ]\n      )\n  },\n  downloadedAt=datetime(2020,1,3).replace(tzinfo=tz.UTC)\n  )\n\n  mkservice.upsertData(auctionRows)\n\n```\n\nUpsert has optional switches that can be applied\n```\nmkservice.upsertData(data, deferCommandExecution, deferDataGeneration, keepNulls, upsertMode)\n```\nThe switch details are,\n\ndeferCommandExecution (true/false) choose between syncronoys and asyncronous command execution, default is false.\ndeferDataGeneration (true/false) choose between syncronoys and asyncronous precomputed data generation, default is true.\nkeepNulls (true/false) if true then nulls are written in the curve replacing any data present for the instant, default is false.\nupsertMode (Merge/Replace) for Auction merge and replace are equivalent. Leaving Null/None/Empty is equivalent to Merge.\n\n\n## Delete Data in Artesian\n\nUsing the MarketDataService is possible to delete MarketData and its curves.\n\n### Delete MarketData in Artesian\n\nUsing the MarketDataService is possible to delete MarketData and its curves.\n\n```Python\n\nfrom Artesian import ArtesianConfig\nfrom Artesian.MarketData import MarketDataService\n\ncfg = ArtesianConfg()\nmkservice = MarketDataService(cfg)\n\nmkservice.deleteMarketData(100042422)\n\n```\n\nDepending on the Type of the MarketData, the DeletData should be composed as per example below. The timezone is optional: for DateSeries if provided must be equal to MarketData OriginalTimezone Default:MarketData OriginalTimezone. For TimeSeries Default:CET\n\n### Delete Data in an Actual Time Series\n\n```Python\nfrom Artesian import ArtesianConfig, Granularity, MarketData\nfrom Artesian.MarketData import AggregationRule\nfrom datetime import datetime\nfrom dateutil import tz\n\ncfg = ArtesianConfg()\n\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\ndeleteData = MarketData.DeleteData(\n    ID=mkdid,\n    timezone='CET',\n    rangeStart=datetime(2020, 1, 1, 6),\n    rangeEnd=datetime(2020, 1, 1, 18),\n)\n\nmkdservice.deleteData(deleteData)\n```\n\n### Delete Data in an Versioned Time Series\n\n```Python\nfrom Artesian import ArtesianConfig, Granularity, MarketData\nfrom Artesian.MarketData import AggregationRule\nfrom datetime import datetime\nfrom dateutil import tz\n\ncfg = ArtesianConfg()\n\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\ndeleteData = MarketData.DeleteData(\n    ID=mkdid,\n    timezone='CET',\n    rangeStart=datetime(2020, 1, 1, 0),\n    rangeEnd=datetime(2020, 1, 7, 0),\n    version=datetime(2020, 1, 1, 0)\n)\n\nmkdservice.deleteData(deleteData)\n```\n\n### Delte Data in a Market Assessment Time Series\n\n```Python\nfrom Artesian import ArtesianConfig, Granularity, MarketData\nfrom datetime import datetime\nfrom dateutil import tz\n\ncfg = ArtesianConfg()\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\ndeleteData = MarketData.DeleteData(\n    ID= mkdid,\n    timezone='CET',\n    rangeStart=datetime(2020, 1, 1, 0),\n    rangeEnd=datetime(2020, 1, 3, 0),\n    product=[\"Feb-20\"]\n)\n\nmkdservice.deleteData(deleteData)\n```\n\n### Delte Data in a Bid Ask Time Series\n\n```Python\nfrom Artesian import ArtesianConfig, Granularity, MarketData\nfrom datetime import datetime\nfrom dateutil import tz\n\ncfg = ArtesianConfg()\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\ndeleteData = MarketData.DeleteData(\n    ID= mkdid,\n    timezone='CET',\n    rangeStart=datetime(2020, 1, 1, 0),\n    rangeEnd=datetime(2020, 1, 3, 0),\n    product=[\"Feb-20\"]\n)\n\nmkdservice.deleteData(deleteData)\n```\n\n### Delete Data in an Auction Time Series\n\n```Python\nfrom Artesian import ArtesianConfig, Granularity, MarketData\nfrom Artesian.MarketData import AggregationRule\nfrom datetime import datetime\nfrom dateutil import tz\n\ncfg = ArtesianConfg()\n\nmkservice = MarketData.MarketDataService(cfg)\n\nmkdid = MarketData.MarketDataIdentifier('PROVIDER', 'MARKETDATANAME')\ndeleteData = MarketData.DeleteData(\n    ID=mkdid,\n    timezone='CET',\n    rangeStart=datetime(2020, 1, 1, 6),\n    rangeEnd=datetime(2020, 1, 1, 18),\n)\n\nmkdservice.deleteData(deleteData)\n```\n\n## Jupyter Support\n\nArtesian SDK uses asyncio internally, this causes a conflict with Jupyter. You can work around this issue by add the following at the beginning of the notebook.\n\n```python\n\n!pip install nest_asyncio\n\nimport nest_asyncio\nnest_asyncio.apply()\n\n\n```\n\n[Issue #3397 with workaround](https://github.com/jupyter/notebook/issues/3397#issuecomment-419386811)\n\n## Links\n\n- [Github](https://github.com/ARKlab/Artesian.SDK-Python)\n- [Ark Energy](http://www.ark-energy.eu/)\n- [Artesian Portal](https://portal.artesian.cloud)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farklab%2Fartesian.sdk-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farklab%2Fartesian.sdk-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farklab%2Fartesian.sdk-python/lists"}