Merge branch 'temp' into gemini
This commit is contained in:
commit
624571ff22
|
|
@ -1,10 +1,12 @@
|
||||||
env/
|
env/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.csv
|
*.csv
|
||||||
src/
|
src/
|
||||||
eval_results/
|
eval_results/
|
||||||
eval_data/
|
eval_data/
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
results/
|
results/
|
||||||
.env
|
.env
|
||||||
|
tradingagents/dataflows/data_cache/
|
||||||
|
CLAUDE.md
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
3.10
|
3.10
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Python Debugger: main.py",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/main.py",
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
402
LICENSE
402
LICENSE
|
|
@ -1,201 +1,201 @@
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
http://www.apache.org/licenses/
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
1. Definitions.
|
1. Definitions.
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
the copyright owner that is granting the License.
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
other entities that control, are controlled by, or are under common
|
other entities that control, are controlled by, or are under common
|
||||||
control with that entity. For the purposes of this definition,
|
control with that entity. For the purposes of this definition,
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
direction or management of such entity, whether by contract or
|
direction or management of such entity, whether by contract or
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
exercising permissions granted by this License.
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
including but not limited to software source code, documentation
|
including but not limited to software source code, documentation
|
||||||
source, and configuration files.
|
source, and configuration files.
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
"Object" form shall mean any form resulting from mechanical
|
||||||
transformation or translation of a Source form, including but
|
transformation or translation of a Source form, including but
|
||||||
not limited to compiled object code, generated documentation,
|
not limited to compiled object code, generated documentation,
|
||||||
and conversions to other media types.
|
and conversions to other media types.
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
Object form, made available under the License, as indicated by a
|
Object form, made available under the License, as indicated by a
|
||||||
copyright notice that is included in or attached to the work
|
copyright notice that is included in or attached to the work
|
||||||
(an example is provided in the Appendix below).
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
form, that is based on (or derived from) the Work and for which the
|
form, that is based on (or derived from) the Work and for which the
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
of this License, Derivative Works shall not include works that remain
|
of this License, Derivative Works shall not include works that remain
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
the Work and Derivative Works thereof.
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
"Contribution" shall mean any work of authorship, including
|
||||||
the original version of the Work and any modifications or additions
|
the original version of the Work and any modifications or additions
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
means any form of electronic, verbal, or written communication sent
|
means any form of electronic, verbal, or written communication sent
|
||||||
to the Licensor or its representatives, including but not limited to
|
to the Licensor or its representatives, including but not limited to
|
||||||
communication on electronic mailing lists, source code control systems,
|
communication on electronic mailing lists, source code control systems,
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
excluding communication that is conspicuously marked or otherwise
|
excluding communication that is conspicuously marked or otherwise
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
subsequently incorporated within the Work.
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
Work and such Derivative Works in Source or Object form.
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
(except as stated in this section) patent license to make, have made,
|
(except as stated in this section) patent license to make, have made,
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
where such license applies only to those patent claims licensable
|
where such license applies only to those patent claims licensable
|
||||||
by such Contributor that are necessarily infringed by their
|
by such Contributor that are necessarily infringed by their
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
institute patent litigation against any entity (including a
|
institute patent litigation against any entity (including a
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
or contributory patent infringement, then any patent licenses
|
or contributory patent infringement, then any patent licenses
|
||||||
granted to You under this License for that Work shall terminate
|
granted to You under this License for that Work shall terminate
|
||||||
as of the date such litigation is filed.
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
modifications, and in Source or Object form, provided that You
|
modifications, and in Source or Object form, provided that You
|
||||||
meet the following conditions:
|
meet the following conditions:
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
(a) You must give any other recipients of the Work or
|
||||||
Derivative Works a copy of this License; and
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
(b) You must cause any modified files to carry prominent notices
|
||||||
stating that You changed the files; and
|
stating that You changed the files; and
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
that You distribute, all copyright, patent, trademark, and
|
that You distribute, all copyright, patent, trademark, and
|
||||||
attribution notices from the Source form of the Work,
|
attribution notices from the Source form of the Work,
|
||||||
excluding those notices that do not pertain to any part of
|
excluding those notices that do not pertain to any part of
|
||||||
the Derivative Works; and
|
the Derivative Works; and
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
distribution, then any Derivative Works that You distribute must
|
distribution, then any Derivative Works that You distribute must
|
||||||
include a readable copy of the attribution notices contained
|
include a readable copy of the attribution notices contained
|
||||||
within such NOTICE file, excluding those notices that do not
|
within such NOTICE file, excluding those notices that do not
|
||||||
pertain to any part of the Derivative Works, in at least one
|
pertain to any part of the Derivative Works, in at least one
|
||||||
of the following places: within a NOTICE text file distributed
|
of the following places: within a NOTICE text file distributed
|
||||||
as part of the Derivative Works; within the Source form or
|
as part of the Derivative Works; within the Source form or
|
||||||
documentation, if provided along with the Derivative Works; or,
|
documentation, if provided along with the Derivative Works; or,
|
||||||
within a display generated by the Derivative Works, if and
|
within a display generated by the Derivative Works, if and
|
||||||
wherever such third-party notices normally appear. The contents
|
wherever such third-party notices normally appear. The contents
|
||||||
of the NOTICE file are for informational purposes only and
|
of the NOTICE file are for informational purposes only and
|
||||||
do not modify the License. You may add Your own attribution
|
do not modify the License. You may add Your own attribution
|
||||||
notices within Derivative Works that You distribute, alongside
|
notices within Derivative Works that You distribute, alongside
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
that such additional attribution notices cannot be construed
|
that such additional attribution notices cannot be construed
|
||||||
as modifying the License.
|
as modifying the License.
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
You may add Your own copyright statement to Your modifications and
|
||||||
may provide additional or different license terms and conditions
|
may provide additional or different license terms and conditions
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
the conditions stated in this License.
|
the conditions stated in this License.
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
this License, without any additional terms or conditions.
|
this License, without any additional terms or conditions.
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
the terms of any separate license agreement you may have executed
|
the terms of any separate license agreement you may have executed
|
||||||
with Licensor regarding such Contributions.
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
except as required for reasonable and customary use in describing the
|
except as required for reasonable and customary use in describing the
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
implied, including, without limitation, any warranties or conditions
|
implied, including, without limitation, any warranties or conditions
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
appropriateness of using or redistributing the Work and assume any
|
appropriateness of using or redistributing the Work and assume any
|
||||||
risks associated with Your exercise of permissions under this License.
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
unless required by applicable law (such as deliberate and grossly
|
unless required by applicable law (such as deliberate and grossly
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
liable to You for damages, including any direct, indirect, special,
|
liable to You for damages, including any direct, indirect, special,
|
||||||
incidental, or consequential damages of any character arising as a
|
incidental, or consequential damages of any character arising as a
|
||||||
result of this License or out of the use or inability to use the
|
result of this License or out of the use or inability to use the
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
other commercial damages or losses), even if such Contributor
|
other commercial damages or losses), even if such Contributor
|
||||||
has been advised of the possibility of such damages.
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
or other liability obligations and/or rights consistent with this
|
or other liability obligations and/or rights consistent with this
|
||||||
License. However, in accepting such obligations, You may act only
|
License. However, in accepting such obligations, You may act only
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
defend, and hold each Contributor harmless for any liability
|
defend, and hold each Contributor harmless for any liability
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
of your accepting any such warranty or additional liability.
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
To apply the Apache License to your work, attach the following
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
replaced with your own identifying information. (Don't include
|
replaced with your own identifying information. (Don't include
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
comment syntax for the file format. We also recommend that a
|
comment syntax for the file format. We also recommend that a
|
||||||
file or class name and description of purpose be included on the
|
file or class name and description of purpose be included on the
|
||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
|
||||||
430
README.md
430
README.md
|
|
@ -1,215 +1,215 @@
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/TauricResearch.png" style="width: 60%; height: auto;">
|
<img src="assets/TauricResearch.png" style="width: 60%; height: auto;">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div align="center" style="line-height: 1;">
|
<div align="center" style="line-height: 1;">
|
||||||
<a href="https://arxiv.org/abs/2412.20138" target="_blank"><img alt="arXiv" src="https://img.shields.io/badge/arXiv-2412.20138-B31B1B?logo=arxiv"/></a>
|
<a href="https://arxiv.org/abs/2412.20138" target="_blank"><img alt="arXiv" src="https://img.shields.io/badge/arXiv-2412.20138-B31B1B?logo=arxiv"/></a>
|
||||||
<a href="https://discord.com/invite/hk9PGKShPK" target="_blank"><img alt="Discord" src="https://img.shields.io/badge/Discord-TradingResearch-7289da?logo=discord&logoColor=white&color=7289da"/></a>
|
<a href="https://discord.com/invite/hk9PGKShPK" target="_blank"><img alt="Discord" src="https://img.shields.io/badge/Discord-TradingResearch-7289da?logo=discord&logoColor=white&color=7289da"/></a>
|
||||||
<a href="./assets/wechat.png" target="_blank"><img alt="WeChat" src="https://img.shields.io/badge/WeChat-TauricResearch-brightgreen?logo=wechat&logoColor=white"/></a>
|
<a href="./assets/wechat.png" target="_blank"><img alt="WeChat" src="https://img.shields.io/badge/WeChat-TauricResearch-brightgreen?logo=wechat&logoColor=white"/></a>
|
||||||
<a href="https://x.com/TauricResearch" target="_blank"><img alt="X Follow" src="https://img.shields.io/badge/X-TauricResearch-white?logo=x&logoColor=white"/></a>
|
<a href="https://x.com/TauricResearch" target="_blank"><img alt="X Follow" src="https://img.shields.io/badge/X-TauricResearch-white?logo=x&logoColor=white"/></a>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://github.com/TauricResearch/" target="_blank"><img alt="Community" src="https://img.shields.io/badge/Join_GitHub_Community-TauricResearch-14C290?logo=discourse"/></a>
|
<a href="https://github.com/TauricResearch/" target="_blank"><img alt="Community" src="https://img.shields.io/badge/Join_GitHub_Community-TauricResearch-14C290?logo=discourse"/></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<!-- Keep these links. Translations will automatically update with the README. -->
|
<!-- Keep these links. Translations will automatically update with the README. -->
|
||||||
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=de">Deutsch</a> |
|
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=de">Deutsch</a> |
|
||||||
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=es">Español</a> |
|
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=es">Español</a> |
|
||||||
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=fr">français</a> |
|
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=fr">français</a> |
|
||||||
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=ja">日本語</a> |
|
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=ja">日本語</a> |
|
||||||
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=ko">한국어</a> |
|
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=ko">한국어</a> |
|
||||||
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=pt">Português</a> |
|
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=pt">Português</a> |
|
||||||
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=ru">Русский</a> |
|
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=ru">Русский</a> |
|
||||||
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=zh">中文</a>
|
<a href="https://www.readme-i18n.com/TauricResearch/TradingAgents?lang=zh">中文</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# TradingAgents: Multi-Agents LLM Financial Trading Framework
|
# TradingAgents: Multi-Agents LLM Financial Trading Framework
|
||||||
|
|
||||||
> 🎉 **TradingAgents** officially released! We have received numerous inquiries about the work, and we would like to express our thanks for the enthusiasm in our community.
|
> 🎉 **TradingAgents** officially released! We have received numerous inquiries about the work, and we would like to express our thanks for the enthusiasm in our community.
|
||||||
>
|
>
|
||||||
> So we decided to fully open-source the framework. Looking forward to building impactful projects with you!
|
> So we decided to fully open-source the framework. Looking forward to building impactful projects with you!
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://www.star-history.com/#TauricResearch/TradingAgents&Date">
|
<a href="https://www.star-history.com/#TauricResearch/TradingAgents&Date">
|
||||||
<picture>
|
<picture>
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=TauricResearch/TradingAgents&type=Date&theme=dark" />
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=TauricResearch/TradingAgents&type=Date&theme=dark" />
|
||||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=TauricResearch/TradingAgents&type=Date" />
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=TauricResearch/TradingAgents&type=Date" />
|
||||||
<img alt="TradingAgents Star History" src="https://api.star-history.com/svg?repos=TauricResearch/TradingAgents&type=Date" style="width: 80%; height: auto;" />
|
<img alt="TradingAgents Star History" src="https://api.star-history.com/svg?repos=TauricResearch/TradingAgents&type=Date" style="width: 80%; height: auto;" />
|
||||||
</picture>
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
🚀 [TradingAgents](#tradingagents-framework) | ⚡ [Installation & CLI](#installation-and-cli) | 🎬 [Demo](https://www.youtube.com/watch?v=90gr5lwjIho) | 📦 [Package Usage](#tradingagents-package) | 🤝 [Contributing](#contributing) | 📄 [Citation](#citation)
|
🚀 [TradingAgents](#tradingagents-framework) | ⚡ [Installation & CLI](#installation-and-cli) | 🎬 [Demo](https://www.youtube.com/watch?v=90gr5lwjIho) | 📦 [Package Usage](#tradingagents-package) | 🤝 [Contributing](#contributing) | 📄 [Citation](#citation)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## TradingAgents Framework
|
## TradingAgents Framework
|
||||||
|
|
||||||
TradingAgents is a multi-agent trading framework that mirrors the dynamics of real-world trading firms. By deploying specialized LLM-powered agents: from fundamental analysts, sentiment experts, and technical analysts, to trader, risk management team, the platform collaboratively evaluates market conditions and informs trading decisions. Moreover, these agents engage in dynamic discussions to pinpoint the optimal strategy.
|
TradingAgents is a multi-agent trading framework that mirrors the dynamics of real-world trading firms. By deploying specialized LLM-powered agents: from fundamental analysts, sentiment experts, and technical analysts, to trader, risk management team, the platform collaboratively evaluates market conditions and informs trading decisions. Moreover, these agents engage in dynamic discussions to pinpoint the optimal strategy.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/schema.png" style="width: 100%; height: auto;">
|
<img src="assets/schema.png" style="width: 100%; height: auto;">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
> TradingAgents framework is designed for research purposes. Trading performance may vary based on many factors, including the chosen backbone language models, model temperature, trading periods, the quality of data, and other non-deterministic factors. [It is not intended as financial, investment, or trading advice.](https://tauric.ai/disclaimer/)
|
> TradingAgents framework is designed for research purposes. Trading performance may vary based on many factors, including the chosen backbone language models, model temperature, trading periods, the quality of data, and other non-deterministic factors. [It is not intended as financial, investment, or trading advice.](https://tauric.ai/disclaimer/)
|
||||||
|
|
||||||
Our framework decomposes complex trading tasks into specialized roles. This ensures the system achieves a robust, scalable approach to market analysis and decision-making.
|
Our framework decomposes complex trading tasks into specialized roles. This ensures the system achieves a robust, scalable approach to market analysis and decision-making.
|
||||||
|
|
||||||
### Analyst Team
|
### Analyst Team
|
||||||
- Fundamentals Analyst: Evaluates company financials and performance metrics, identifying intrinsic values and potential red flags.
|
- Fundamentals Analyst: Evaluates company financials and performance metrics, identifying intrinsic values and potential red flags.
|
||||||
- Sentiment Analyst: Analyzes social media and public sentiment using sentiment scoring algorithms to gauge short-term market mood.
|
- Sentiment Analyst: Analyzes social media and public sentiment using sentiment scoring algorithms to gauge short-term market mood.
|
||||||
- News Analyst: Monitors global news and macroeconomic indicators, interpreting the impact of events on market conditions.
|
- News Analyst: Monitors global news and macroeconomic indicators, interpreting the impact of events on market conditions.
|
||||||
- Technical Analyst: Utilizes technical indicators (like MACD and RSI) to detect trading patterns and forecast price movements.
|
- Technical Analyst: Utilizes technical indicators (like MACD and RSI) to detect trading patterns and forecast price movements.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/analyst.png" width="100%" style="display: inline-block; margin: 0 2%;">
|
<img src="assets/analyst.png" width="100%" style="display: inline-block; margin: 0 2%;">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
### Researcher Team
|
### Researcher Team
|
||||||
- Comprises both bullish and bearish researchers who critically assess the insights provided by the Analyst Team. Through structured debates, they balance potential gains against inherent risks.
|
- Comprises both bullish and bearish researchers who critically assess the insights provided by the Analyst Team. Through structured debates, they balance potential gains against inherent risks.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/researcher.png" width="70%" style="display: inline-block; margin: 0 2%;">
|
<img src="assets/researcher.png" width="70%" style="display: inline-block; margin: 0 2%;">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
### Trader Agent
|
### Trader Agent
|
||||||
- Composes reports from the analysts and researchers to make informed trading decisions. It determines the timing and magnitude of trades based on comprehensive market insights.
|
- Composes reports from the analysts and researchers to make informed trading decisions. It determines the timing and magnitude of trades based on comprehensive market insights.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/trader.png" width="70%" style="display: inline-block; margin: 0 2%;">
|
<img src="assets/trader.png" width="70%" style="display: inline-block; margin: 0 2%;">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
### Risk Management and Portfolio Manager
|
### Risk Management and Portfolio Manager
|
||||||
- Continuously evaluates portfolio risk by assessing market volatility, liquidity, and other risk factors. The risk management team evaluates and adjusts trading strategies, providing assessment reports to the Portfolio Manager for final decision.
|
- Continuously evaluates portfolio risk by assessing market volatility, liquidity, and other risk factors. The risk management team evaluates and adjusts trading strategies, providing assessment reports to the Portfolio Manager for final decision.
|
||||||
- The Portfolio Manager approves/rejects the transaction proposal. If approved, the order will be sent to the simulated exchange and executed.
|
- The Portfolio Manager approves/rejects the transaction proposal. If approved, the order will be sent to the simulated exchange and executed.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/risk.png" width="70%" style="display: inline-block; margin: 0 2%;">
|
<img src="assets/risk.png" width="70%" style="display: inline-block; margin: 0 2%;">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Installation and CLI
|
## Installation and CLI
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
Clone TradingAgents:
|
Clone TradingAgents:
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/TauricResearch/TradingAgents.git
|
git clone https://github.com/TauricResearch/TradingAgents.git
|
||||||
cd TradingAgents
|
cd TradingAgents
|
||||||
```
|
```
|
||||||
|
|
||||||
Create a virtual environment in any of your favorite environment managers:
|
Create a virtual environment in any of your favorite environment managers:
|
||||||
```bash
|
```bash
|
||||||
conda create -n tradingagents python=3.13
|
conda create -n tradingagents python=3.13
|
||||||
conda activate tradingagents
|
conda activate tradingagents
|
||||||
```
|
```
|
||||||
|
|
||||||
Install dependencies:
|
Install dependencies:
|
||||||
```bash
|
```bash
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
### Required APIs
|
### Required APIs
|
||||||
|
|
||||||
You will also need the FinnHub API for financial data. All of our code is implemented with the free tier.
|
You will also need the FinnHub API for financial data. All of our code is implemented with the free tier.
|
||||||
```bash
|
```bash
|
||||||
export FINNHUB_API_KEY=$YOUR_FINNHUB_API_KEY
|
export FINNHUB_API_KEY=$YOUR_FINNHUB_API_KEY
|
||||||
```
|
```
|
||||||
|
|
||||||
You will need the OpenAI API or GEMINI API for all the agents.
|
You will need the OpenAI API or GEMINI API for all the agents.
|
||||||
```bash
|
```bash
|
||||||
export OPENAI_API_KEY=$YOUR_OPENAI_API_KEY
|
export OPENAI_API_KEY=$YOUR_OPENAI_API_KEY
|
||||||
export GEMINI_API_KEY=$YOUR_GEMINI_API_KEY
|
export GEMINI_API_KEY=$YOUR_GEMINI_API_KEY
|
||||||
export GOOGLE_API_KEY=$YOUR_GEMINI_API_KEY
|
export GOOGLE_API_KEY=$YOUR_GEMINI_API_KEY
|
||||||
```
|
```
|
||||||
|
|
||||||
### CLI Usage
|
### CLI Usage
|
||||||
|
|
||||||
You can also try out the CLI directly by running:
|
You can also try out the CLI directly by running:
|
||||||
```bash
|
```bash
|
||||||
python -m cli.main
|
python -m cli.main
|
||||||
```
|
```
|
||||||
You will see a screen where you can select your desired tickers, date, LLMs, research depth, etc.
|
You will see a screen where you can select your desired tickers, date, LLMs, research depth, etc.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/cli/cli_init.png" width="100%" style="display: inline-block; margin: 0 2%;">
|
<img src="assets/cli/cli_init.png" width="100%" style="display: inline-block; margin: 0 2%;">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
An interface will appear showing results as they load, letting you track the agent's progress as it runs.
|
An interface will appear showing results as they load, letting you track the agent's progress as it runs.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/cli/cli_news.png" width="100%" style="display: inline-block; margin: 0 2%;">
|
<img src="assets/cli/cli_news.png" width="100%" style="display: inline-block; margin: 0 2%;">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/cli/cli_transaction.png" width="100%" style="display: inline-block; margin: 0 2%;">
|
<img src="assets/cli/cli_transaction.png" width="100%" style="display: inline-block; margin: 0 2%;">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## TradingAgents Package
|
## TradingAgents Package
|
||||||
|
|
||||||
### Implementation Details
|
### Implementation Details
|
||||||
|
|
||||||
We built TradingAgents with LangGraph to ensure flexibility and modularity. We utilize `o1-preview` and `gpt-4o` as our deep thinking and fast thinking LLMs for our experiments. However, for testing purposes, we recommend you use `o4-mini` and `gpt-4.1-mini` to save on costs as our framework makes **lots of** API calls.
|
We built TradingAgents with LangGraph to ensure flexibility and modularity. We utilize `o1-preview` and `gpt-4o` as our deep thinking and fast thinking LLMs for our experiments. However, for testing purposes, we recommend you use `o4-mini` and `gpt-4.1-mini` to save on costs as our framework makes **lots of** API calls.
|
||||||
|
|
||||||
### Python Usage
|
### Python Usage
|
||||||
|
|
||||||
To use TradingAgents inside your code, you can import the `tradingagents` module and initialize a `TradingAgentsGraph()` object. The `.propagate()` function will return a decision. You can run `main.py`, here's also a quick example:
|
To use TradingAgents inside your code, you can import the `tradingagents` module and initialize a `TradingAgentsGraph()` object. The `.propagate()` function will return a decision. You can run `main.py`, here's also a quick example:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
||||||
from tradingagents.default_config import DEFAULT_CONFIG
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
|
||||||
ta = TradingAgentsGraph(debug=True, config=DEFAULT_CONFIG.copy())
|
ta = TradingAgentsGraph(debug=True, config=DEFAULT_CONFIG.copy())
|
||||||
|
|
||||||
# forward propagate
|
# forward propagate
|
||||||
_, decision = ta.propagate("NVDA", "2024-05-10")
|
_, decision = ta.propagate("NVDA", "2024-05-10")
|
||||||
print(decision)
|
print(decision)
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also adjust the default configuration to set your own choice of LLMs, debate rounds, etc.
|
You can also adjust the default configuration to set your own choice of LLMs, debate rounds, etc.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
||||||
from tradingagents.default_config import DEFAULT_CONFIG
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
|
||||||
# Create a custom config
|
# Create a custom config
|
||||||
config = DEFAULT_CONFIG.copy()
|
config = DEFAULT_CONFIG.copy()
|
||||||
config["deep_think_llm"] = "gpt-4.1-nano" # Use a different model
|
config["deep_think_llm"] = "gpt-4.1-nano" # Use a different model
|
||||||
config["quick_think_llm"] = "gpt-4.1-nano" # Use a different model
|
config["quick_think_llm"] = "gpt-4.1-nano" # Use a different model
|
||||||
config["max_debate_rounds"] = 1 # Increase debate rounds
|
config["max_debate_rounds"] = 1 # Increase debate rounds
|
||||||
config["online_tools"] = True # Use online tools or cached data
|
config["online_tools"] = True # Use online tools or cached data
|
||||||
|
|
||||||
# Initialize with custom config
|
# Initialize with custom config
|
||||||
ta = TradingAgentsGraph(debug=True, config=config)
|
ta = TradingAgentsGraph(debug=True, config=config)
|
||||||
|
|
||||||
# forward propagate
|
# forward propagate
|
||||||
_, decision = ta.propagate("NVDA", "2024-05-10")
|
_, decision = ta.propagate("NVDA", "2024-05-10")
|
||||||
print(decision)
|
print(decision)
|
||||||
```
|
```
|
||||||
|
|
||||||
> For `online_tools`, we recommend enabling them for experimentation, as they provide access to real-time data. The agents' offline tools rely on cached data from our **Tauric TradingDB**, a curated dataset we use for backtesting. We're currently in the process of refining this dataset, and we plan to release it soon alongside our upcoming projects. Stay tuned!
|
> For `online_tools`, we recommend enabling them for experimentation, as they provide access to real-time data. The agents' offline tools rely on cached data from our **Tauric TradingDB**, a curated dataset we use for backtesting. We're currently in the process of refining this dataset, and we plan to release it soon alongside our upcoming projects. Stay tuned!
|
||||||
|
|
||||||
You can view the full list of configurations in `tradingagents/default_config.py`.
|
You can view the full list of configurations in `tradingagents/default_config.py`.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
We welcome contributions from the community! Whether it's fixing a bug, improving documentation, or suggesting a new feature, your input helps make this project better. If you are interested in this line of research, please consider joining our open-source financial AI research community [Tauric Research](https://tauric.ai/).
|
We welcome contributions from the community! Whether it's fixing a bug, improving documentation, or suggesting a new feature, your input helps make this project better. If you are interested in this line of research, please consider joining our open-source financial AI research community [Tauric Research](https://tauric.ai/).
|
||||||
|
|
||||||
## Citation
|
## Citation
|
||||||
|
|
||||||
Please reference our work if you find *TradingAgents* provides you with some help :)
|
Please reference our work if you find *TradingAgents* provides you with some help :)
|
||||||
|
|
||||||
```
|
```
|
||||||
@misc{xiao2025tradingagentsmultiagentsllmfinancial,
|
@misc{xiao2025tradingagentsmultiagentsllmfinancial,
|
||||||
title={TradingAgents: Multi-Agents LLM Financial Trading Framework},
|
title={TradingAgents: Multi-Agents LLM Financial Trading Framework},
|
||||||
author={Yijia Xiao and Edward Sun and Di Luo and Wei Wang},
|
author={Yijia Xiao and Edward Sun and Di Luo and Wei Wang},
|
||||||
year={2025},
|
year={2025},
|
||||||
eprint={2412.20138},
|
eprint={2412.20138},
|
||||||
archivePrefix={arXiv},
|
archivePrefix={arXiv},
|
||||||
primaryClass={q-fin.TR},
|
primaryClass={q-fin.TR},
|
||||||
url={https://arxiv.org/abs/2412.20138},
|
url={https://arxiv.org/abs/2412.20138},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,8 @@ def select_shallow_thinking_agent(provider) -> str:
|
||||||
("GPT-4.1-nano - Ultra-lightweight model for basic operations", "gpt-4.1-nano"),
|
("GPT-4.1-nano - Ultra-lightweight model for basic operations", "gpt-4.1-nano"),
|
||||||
("GPT-4.1-mini - Compact model with good performance", "gpt-4.1-mini"),
|
("GPT-4.1-mini - Compact model with good performance", "gpt-4.1-mini"),
|
||||||
("GPT-4o - Standard model with solid capabilities", "gpt-4o"),
|
("GPT-4o - Standard model with solid capabilities", "gpt-4o"),
|
||||||
|
("o4-mini - Specialized reasoning model (compact)", "o4-mini"),
|
||||||
|
("o3 - Full advanced reasoning model", "o3"),
|
||||||
],
|
],
|
||||||
"anthropic": [
|
"anthropic": [
|
||||||
("Claude Haiku 3.5 - Fast inference and standard capabilities", "claude-3-5-haiku-latest"),
|
("Claude Haiku 3.5 - Fast inference and standard capabilities", "claude-3-5-haiku-latest"),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: tradingagents_mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-password}
|
||||||
|
MYSQL_DATABASE: ${DB_NAME:-tradingagents_db}
|
||||||
|
MYSQL_USER: ${DB_USER:-tradinguser}
|
||||||
|
MYSQL_PASSWORD: ${DB_PASSWORD:-password}
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
volumes:
|
||||||
|
- /home/hskim/mysql_data:/var/lib/mysql
|
||||||
|
- /home/hskim/docker/mysql/init:/docker-entrypoint-initdb.d
|
||||||
|
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||||
|
networks:
|
||||||
|
- tradingagents_network
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: tradingagents_redis
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
command: redis-server --appendonly yes
|
||||||
|
networks:
|
||||||
|
- tradingagents_network
|
||||||
|
|
||||||
|
# 개발용 phpMyAdmin (선택사항)
|
||||||
|
# phpmyadmin:
|
||||||
|
# image: phpmyadmin/phpmyadmin
|
||||||
|
# container_name: tradingagents_phpmyadmin
|
||||||
|
# restart: unless-stopped
|
||||||
|
# environment:
|
||||||
|
# PMA_HOST: mysql
|
||||||
|
# PMA_PORT: 3306
|
||||||
|
# PMA_USER: root
|
||||||
|
# PMA_PASSWORD: ${DB_PASSWORD:-password}
|
||||||
|
# ports:
|
||||||
|
# - "8080:80"
|
||||||
|
# depends_on:
|
||||||
|
# - mysql
|
||||||
|
# networks:
|
||||||
|
# - tradingagents_network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql_data:
|
||||||
|
driver: local
|
||||||
|
redis_data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
tradingagents_network:
|
||||||
|
driver: bridge
|
||||||
21
main.py
21
main.py
|
|
@ -1,21 +0,0 @@
|
||||||
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
|
||||||
from tradingagents.default_config import DEFAULT_CONFIG
|
|
||||||
|
|
||||||
# Create a custom config
|
|
||||||
config = DEFAULT_CONFIG.copy()
|
|
||||||
config["llm_provider"] = "google" # Use a different model
|
|
||||||
config["backend_url"] = "https://generativelanguage.googleapis.com/v1" # Use a different backend
|
|
||||||
config["deep_think_llm"] = "gemini-2.5-pro" # Use a different model
|
|
||||||
config["quick_think_llm"] = "gemini-2.5-flash-lite-preview-06-17" # Use a different model
|
|
||||||
config["max_debate_rounds"] = 1 # Increase debate rounds
|
|
||||||
config["online_tools"] = True # Increase debate rounds
|
|
||||||
|
|
||||||
# Initialize with custom config
|
|
||||||
ta = TradingAgentsGraph(debug=True, config=config)
|
|
||||||
|
|
||||||
# forward propagate
|
|
||||||
_, decision = ta.propagate("NVDA", "2024-05-10")
|
|
||||||
print(decision)
|
|
||||||
|
|
||||||
# Memorize mistakes and reflect
|
|
||||||
# ta.reflect_and_remember(1000) # parameter is the position returns
|
|
||||||
|
|
@ -1,34 +1,34 @@
|
||||||
[project]
|
[project]
|
||||||
name = "tradingagents"
|
name = "tradingagents"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Add your description here"
|
description = "Add your description here"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"akshare>=1.16.98",
|
"akshare>=1.16.98",
|
||||||
"backtrader>=1.9.78.123",
|
"backtrader>=1.9.78.123",
|
||||||
"chainlit>=2.5.5",
|
"chainlit>=2.5.5",
|
||||||
"chromadb>=1.0.12",
|
"chromadb>=1.0.12",
|
||||||
"eodhd>=1.0.32",
|
"eodhd>=1.0.32",
|
||||||
"feedparser>=6.0.11",
|
"feedparser>=6.0.11",
|
||||||
"finnhub-python>=2.4.23",
|
"finnhub-python>=2.4.23",
|
||||||
"langchain-anthropic>=0.3.15",
|
"langchain-anthropic>=0.3.15",
|
||||||
"langchain-experimental>=0.3.4",
|
"langchain-experimental>=0.3.4",
|
||||||
"langchain-google-genai>=2.1.5",
|
"langchain-google-genai>=2.1.5",
|
||||||
"langchain-openai>=0.3.23",
|
"langchain-openai>=0.3.23",
|
||||||
"langgraph>=0.4.8",
|
"langgraph>=0.4.8",
|
||||||
"pandas>=2.3.0",
|
"pandas>=2.3.0",
|
||||||
"parsel>=1.10.0",
|
"parsel>=1.10.0",
|
||||||
"praw>=7.8.1",
|
"praw>=7.8.1",
|
||||||
"pytz>=2025.2",
|
"pytz>=2025.2",
|
||||||
"questionary>=2.1.0",
|
"questionary>=2.1.0",
|
||||||
"redis>=6.2.0",
|
"redis>=6.2.0",
|
||||||
"requests>=2.32.4",
|
"requests>=2.32.4",
|
||||||
"rich>=14.0.0",
|
"rich>=14.0.0",
|
||||||
"setuptools>=80.9.0",
|
"setuptools>=80.9.0",
|
||||||
"stockstats>=0.6.5",
|
"stockstats>=0.6.5",
|
||||||
"tqdm>=4.67.1",
|
"tqdm>=4.67.1",
|
||||||
"tushare>=1.4.21",
|
"tushare>=1.4.21",
|
||||||
"typing-extensions>=4.14.0",
|
"typing-extensions>=4.14.0",
|
||||||
"yfinance>=0.2.63",
|
"yfinance>=0.2.63",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,27 @@
|
||||||
typing-extensions
|
typing-extensions
|
||||||
langchain-openai
|
langchain-openai
|
||||||
langchain-experimental
|
langchain-experimental
|
||||||
pandas
|
pandas
|
||||||
yfinance
|
yfinance
|
||||||
praw
|
praw
|
||||||
feedparser
|
feedparser
|
||||||
stockstats
|
stockstats
|
||||||
eodhd
|
eodhd
|
||||||
langgraph
|
langgraph
|
||||||
chromadb
|
chromadb
|
||||||
setuptools
|
setuptools
|
||||||
backtrader
|
backtrader
|
||||||
akshare
|
akshare
|
||||||
tushare
|
tushare
|
||||||
finnhub-python
|
finnhub-python
|
||||||
parsel
|
parsel
|
||||||
requests
|
requests
|
||||||
tqdm
|
tqdm
|
||||||
pytz
|
pytz
|
||||||
redis
|
redis
|
||||||
chainlit
|
chainlit
|
||||||
rich
|
rich
|
||||||
questionary
|
questionary
|
||||||
langchain_anthropic
|
langchain_anthropic
|
||||||
langchain-google-genai
|
langchain-google-genai
|
||||||
google-genai
|
google-genai
|
||||||
|
|
|
||||||
86
setup.py
86
setup.py
|
|
@ -1,43 +1,43 @@
|
||||||
"""
|
"""
|
||||||
Setup script for the TradingAgents package.
|
Setup script for the TradingAgents package.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="tradingagents",
|
name="tradingagents",
|
||||||
version="0.1.0",
|
version="0.1.0",
|
||||||
description="Multi-Agents LLM Financial Trading Framework",
|
description="Multi-Agents LLM Financial Trading Framework",
|
||||||
author="TradingAgents Team",
|
author="TradingAgents Team",
|
||||||
author_email="yijia.xiao@cs.ucla.edu",
|
author_email="yijia.xiao@cs.ucla.edu",
|
||||||
url="https://github.com/TauricResearch",
|
url="https://github.com/TauricResearch",
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"langchain>=0.1.0",
|
"langchain>=0.1.0",
|
||||||
"langchain-openai>=0.0.2",
|
"langchain-openai>=0.0.2",
|
||||||
"langchain-experimental>=0.0.40",
|
"langchain-experimental>=0.0.40",
|
||||||
"langgraph>=0.0.20",
|
"langgraph>=0.0.20",
|
||||||
"numpy>=1.24.0",
|
"numpy>=1.24.0",
|
||||||
"pandas>=2.0.0",
|
"pandas>=2.0.0",
|
||||||
"praw>=7.7.0",
|
"praw>=7.7.0",
|
||||||
"stockstats>=0.5.4",
|
"stockstats>=0.5.4",
|
||||||
"yfinance>=0.2.31",
|
"yfinance>=0.2.31",
|
||||||
"typer>=0.9.0",
|
"typer>=0.9.0",
|
||||||
"rich>=13.0.0",
|
"rich>=13.0.0",
|
||||||
"questionary>=2.0.1",
|
"questionary>=2.0.1",
|
||||||
],
|
],
|
||||||
python_requires=">=3.10",
|
python_requires=">=3.10",
|
||||||
entry_points={
|
entry_points={
|
||||||
"console_scripts": [
|
"console_scripts": [
|
||||||
"tradingagents=cli.main:app",
|
"tradingagents=cli.main:app",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 3 - Alpha",
|
"Development Status :: 3 - Alpha",
|
||||||
"Intended Audience :: Financial and Trading Industry",
|
"Intended Audience :: Financial and Trading Industry",
|
||||||
"License :: OSI Approved :: Apache Software License",
|
"License :: OSI Approved :: Apache Software License",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Topic :: Office/Business :: Financial :: Investment",
|
"Topic :: Office/Business :: Financial :: Investment",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ from .embedding_providers import (
|
||||||
GeminiEmbeddingProvider,
|
GeminiEmbeddingProvider,
|
||||||
OllamaEmbeddingProvider
|
OllamaEmbeddingProvider
|
||||||
)
|
)
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
class EmbeddingProviderFactory:
|
class EmbeddingProviderFactory:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_provider(config : dict[str, any])->EmbeddingProvider:
|
def create_provider(config : dict[str, Any])->EmbeddingProvider:
|
||||||
backend_url = config["backend_url"]
|
backend_url = config["backend_url"]
|
||||||
|
|
||||||
if "generativelanguage.googleapis.com" in backend_url:
|
if "generativelanguage.googleapis.com" in backend_url:
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from typing import Dict, Optional
|
||||||
|
|
||||||
# Use default config but allow it to be overridden
|
# Use default config but allow it to be overridden
|
||||||
_config: Optional[Dict] = None
|
_config: Optional[Dict] = None
|
||||||
DATA_DIR: Optional[str] = None
|
DATA_DIR: str = ""
|
||||||
|
|
||||||
|
|
||||||
def initialize_config():
|
def initialize_config():
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,14 @@ def getNewsData(query, start_date, end_date):
|
||||||
for el in results_on_page:
|
for el in results_on_page:
|
||||||
try:
|
try:
|
||||||
link = el.find("a")["href"]
|
link = el.find("a")["href"]
|
||||||
title = el.select_one("div.MBeuO").get_text()
|
title_el = el.select_one("div.MBeuO")
|
||||||
snippet = el.select_one(".GI74Re").get_text()
|
title = title_el.get_text() if title_el else ""
|
||||||
date = el.select_one(".LfVVr").get_text()
|
snippet_el = el.select_one(".GI74Re")
|
||||||
source = el.select_one(".NUnG9d span").get_text()
|
snippet = snippet_el.get_text() if snippet_el else ""
|
||||||
|
date_el = el.select_one(".LfVVr")
|
||||||
|
date = date_el.get_text() if date_el else ""
|
||||||
|
source_el = el.select_one(".NUnG9d span")
|
||||||
|
source = source_el.get_text() if source_el else ""
|
||||||
news_results.append(
|
news_results.append(
|
||||||
{
|
{
|
||||||
"link": link,
|
"link": link,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Annotated, Dict
|
from typing import Annotated, Dict, Tuple
|
||||||
from .reddit_utils import fetch_top_from_category
|
from .reddit_utils import fetch_top_from_category
|
||||||
from .yfin_utils import *
|
from .yfin_utils import *
|
||||||
from .stockstats_utils import *
|
from .stockstats_utils import *
|
||||||
|
|
@ -14,7 +14,24 @@ from tqdm import tqdm
|
||||||
import yfinance as yf
|
import yfinance as yf
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from .config import get_config, set_config, DATA_DIR
|
from .config import get_config, set_config, DATA_DIR
|
||||||
from .search_provider_factory import SearchProviderFactory
|
from .search_provider_factory import SearchProviderFactory, create_search_provider_factory
|
||||||
|
|
||||||
|
|
||||||
|
def parse_date_range(curr_date: str, look_back_days: int) -> Tuple[str, str]:
|
||||||
|
"""
|
||||||
|
Parse date range and return start and end dates.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
curr_date: Current date in yyyy-mm-dd format
|
||||||
|
look_back_days: Number of days to look back
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (start_date, end_date) as strings
|
||||||
|
"""
|
||||||
|
end_date = curr_date
|
||||||
|
start_date_obj = datetime.strptime(curr_date, "%Y-%m-%d")
|
||||||
|
before = start_date_obj - relativedelta(days=look_back_days)
|
||||||
|
return before.strftime("%Y-%m-%d"), end_date
|
||||||
|
|
||||||
|
|
||||||
def get_finnhub_news(
|
def get_finnhub_news(
|
||||||
|
|
@ -37,9 +54,7 @@ def get_finnhub_news(
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
start_date = datetime.strptime(curr_date, "%Y-%m-%d")
|
before, _ = parse_date_range(curr_date, look_back_days)
|
||||||
before = start_date - relativedelta(days=look_back_days)
|
|
||||||
before = before.strftime("%Y-%m-%d")
|
|
||||||
|
|
||||||
result = get_data_in_range(ticker, before, curr_date, "news_data", DATA_DIR)
|
result = get_data_in_range(ticker, before, curr_date, "news_data", DATA_DIR)
|
||||||
|
|
||||||
|
|
@ -76,9 +91,7 @@ def get_finnhub_company_insider_sentiment(
|
||||||
str: a report of the sentiment in the past 15 days starting at curr_date
|
str: a report of the sentiment in the past 15 days starting at curr_date
|
||||||
"""
|
"""
|
||||||
|
|
||||||
date_obj = datetime.strptime(curr_date, "%Y-%m-%d")
|
before, _ = parse_date_range(curr_date, look_back_days)
|
||||||
before = date_obj - relativedelta(days=look_back_days)
|
|
||||||
before = before.strftime("%Y-%m-%d")
|
|
||||||
|
|
||||||
data = get_data_in_range(ticker, before, curr_date, "insider_senti", DATA_DIR)
|
data = get_data_in_range(ticker, before, curr_date, "insider_senti", DATA_DIR)
|
||||||
|
|
||||||
|
|
@ -117,9 +130,7 @@ def get_finnhub_company_insider_transactions(
|
||||||
str: a report of the company's insider transaction/trading informtaion in the past 15 days
|
str: a report of the company's insider transaction/trading informtaion in the past 15 days
|
||||||
"""
|
"""
|
||||||
|
|
||||||
date_obj = datetime.strptime(curr_date, "%Y-%m-%d")
|
before, _ = parse_date_range(curr_date, look_back_days)
|
||||||
before = date_obj - relativedelta(days=look_back_days)
|
|
||||||
before = before.strftime("%Y-%m-%d")
|
|
||||||
|
|
||||||
data = get_data_in_range(ticker, before, curr_date, "insider_trans", DATA_DIR)
|
data = get_data_in_range(ticker, before, curr_date, "insider_trans", DATA_DIR)
|
||||||
|
|
||||||
|
|
@ -290,9 +301,7 @@ def get_google_news(
|
||||||
) -> str:
|
) -> str:
|
||||||
query = query.replace(" ", "+")
|
query = query.replace(" ", "+")
|
||||||
|
|
||||||
start_date = datetime.strptime(curr_date, "%Y-%m-%d")
|
before, _ = parse_date_range(curr_date, look_back_days)
|
||||||
before = start_date - relativedelta(days=look_back_days)
|
|
||||||
before = before.strftime("%Y-%m-%d")
|
|
||||||
|
|
||||||
news_results = getNewsData(query, before, curr_date)
|
news_results = getNewsData(query, before, curr_date)
|
||||||
|
|
||||||
|
|
@ -323,18 +332,17 @@ def get_reddit_global_news(
|
||||||
str: A formatted dataframe containing the latest news articles posts on reddit and meta information in these columns: "created_utc", "id", "title", "selftext", "score", "num_comments", "url"
|
str: A formatted dataframe containing the latest news articles posts on reddit and meta information in these columns: "created_utc", "id", "title", "selftext", "score", "num_comments", "url"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
start_date = datetime.strptime(start_date, "%Y-%m-%d")
|
before, start_date_str = parse_date_range(start_date, look_back_days)
|
||||||
before = start_date - relativedelta(days=look_back_days)
|
start_date_dt = datetime.strptime(start_date_str, "%Y-%m-%d")
|
||||||
before = before.strftime("%Y-%m-%d")
|
|
||||||
|
|
||||||
posts = []
|
posts = []
|
||||||
# iterate from start_date to end_date
|
# iterate from start_date to end_date
|
||||||
curr_date = datetime.strptime(before, "%Y-%m-%d")
|
curr_date = datetime.strptime(before, "%Y-%m-%d")
|
||||||
|
|
||||||
total_iterations = (start_date - curr_date).days + 1
|
total_iterations = (start_date_dt - curr_date).days + 1
|
||||||
pbar = tqdm(desc=f"Getting Global News on {start_date}", total=total_iterations)
|
pbar = tqdm(desc=f"Getting Global News on {start_date_dt}", total=total_iterations)
|
||||||
|
|
||||||
while curr_date <= start_date:
|
while curr_date <= start_date_dt:
|
||||||
curr_date_str = curr_date.strftime("%Y-%m-%d")
|
curr_date_str = curr_date.strftime("%Y-%m-%d")
|
||||||
fetch_result = fetch_top_from_category(
|
fetch_result = fetch_top_from_category(
|
||||||
"global_news",
|
"global_news",
|
||||||
|
|
@ -377,21 +385,20 @@ def get_reddit_company_news(
|
||||||
str: A formatted dataframe containing the latest news articles posts on reddit and meta information in these columns: "created_utc", "id", "title", "selftext", "score", "num_comments", "url"
|
str: A formatted dataframe containing the latest news articles posts on reddit and meta information in these columns: "created_utc", "id", "title", "selftext", "score", "num_comments", "url"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
start_date = datetime.strptime(start_date, "%Y-%m-%d")
|
before, start_date_str = parse_date_range(start_date, look_back_days)
|
||||||
before = start_date - relativedelta(days=look_back_days)
|
start_date_dt = datetime.strptime(start_date_str, "%Y-%m-%d")
|
||||||
before = before.strftime("%Y-%m-%d")
|
|
||||||
|
|
||||||
posts = []
|
posts = []
|
||||||
# iterate from start_date to end_date
|
# iterate from start_date to end_date
|
||||||
curr_date = datetime.strptime(before, "%Y-%m-%d")
|
curr_date = datetime.strptime(before, "%Y-%m-%d")
|
||||||
|
|
||||||
total_iterations = (start_date - curr_date).days + 1
|
total_iterations = (start_date_dt - curr_date).days + 1
|
||||||
pbar = tqdm(
|
pbar = tqdm(
|
||||||
desc=f"Getting Company News for {ticker} on {start_date}",
|
desc=f"Getting Company News for {ticker} on {start_date_dt}",
|
||||||
total=total_iterations,
|
total=total_iterations,
|
||||||
)
|
)
|
||||||
|
|
||||||
while curr_date <= start_date:
|
while curr_date <= start_date_dt:
|
||||||
curr_date_str = curr_date.strftime("%Y-%m-%d")
|
curr_date_str = curr_date.strftime("%Y-%m-%d")
|
||||||
fetch_result = fetch_top_from_category(
|
fetch_result = fetch_top_from_category(
|
||||||
"company_news",
|
"company_news",
|
||||||
|
|
@ -509,8 +516,9 @@ def get_stock_stats_indicators_window(
|
||||||
)
|
)
|
||||||
|
|
||||||
end_date = curr_date
|
end_date = curr_date
|
||||||
curr_date = datetime.strptime(curr_date, "%Y-%m-%d")
|
before_str, _ = parse_date_range(curr_date, look_back_days)
|
||||||
before = curr_date - relativedelta(days=look_back_days)
|
before_dt = datetime.strptime(before_str, "%Y-%m-%d")
|
||||||
|
curr_date_dt = datetime.strptime(curr_date, "%Y-%m-%d")
|
||||||
|
|
||||||
if not online:
|
if not online:
|
||||||
# read from YFin data
|
# read from YFin data
|
||||||
|
|
@ -524,30 +532,30 @@ def get_stock_stats_indicators_window(
|
||||||
dates_in_df = data["Date"].astype(str).str[:10]
|
dates_in_df = data["Date"].astype(str).str[:10]
|
||||||
|
|
||||||
ind_string = ""
|
ind_string = ""
|
||||||
while curr_date >= before:
|
while curr_date_dt >= before_dt:
|
||||||
# only do the trading dates
|
# only do the trading dates
|
||||||
if curr_date.strftime("%Y-%m-%d") in dates_in_df.values:
|
if curr_date_dt.strftime("%Y-%m-%d") in dates_in_df.values:
|
||||||
indicator_value = get_stockstats_indicator(
|
indicator_value = get_stockstats_indicator(
|
||||||
symbol, indicator, curr_date.strftime("%Y-%m-%d"), online
|
symbol, indicator, curr_date_dt.strftime("%Y-%m-%d"), online
|
||||||
)
|
)
|
||||||
|
|
||||||
ind_string += f"{curr_date.strftime('%Y-%m-%d')}: {indicator_value}\n"
|
ind_string += f"{curr_date_dt.strftime('%Y-%m-%d')}: {indicator_value}\n"
|
||||||
|
|
||||||
curr_date = curr_date - relativedelta(days=1)
|
curr_date_dt = curr_date_dt - relativedelta(days=1)
|
||||||
else:
|
else:
|
||||||
# online gathering
|
# online gathering
|
||||||
ind_string = ""
|
ind_string = ""
|
||||||
while curr_date >= before:
|
while curr_date_dt >= before_dt:
|
||||||
indicator_value = get_stockstats_indicator(
|
indicator_value = get_stockstats_indicator(
|
||||||
symbol, indicator, curr_date.strftime("%Y-%m-%d"), online
|
symbol, indicator, curr_date_dt.strftime("%Y-%m-%d"), online
|
||||||
)
|
)
|
||||||
|
|
||||||
ind_string += f"{curr_date.strftime('%Y-%m-%d')}: {indicator_value}\n"
|
ind_string += f"{curr_date_dt.strftime('%Y-%m-%d')}: {indicator_value}\n"
|
||||||
|
|
||||||
curr_date = curr_date - relativedelta(days=1)
|
curr_date_dt = curr_date_dt - relativedelta(days=1)
|
||||||
|
|
||||||
result_str = (
|
result_str = (
|
||||||
f"## {indicator} values from {before.strftime('%Y-%m-%d')} to {end_date}:\n\n"
|
f"## {indicator} values from {before_dt.strftime('%Y-%m-%d')} to {end_date}:\n\n"
|
||||||
+ ind_string
|
+ ind_string
|
||||||
+ "\n\n"
|
+ "\n\n"
|
||||||
+ best_ind_params.get(indicator, "No description available.")
|
+ best_ind_params.get(indicator, "No description available.")
|
||||||
|
|
@ -565,20 +573,20 @@ def get_stockstats_indicator(
|
||||||
online: Annotated[bool, "to fetch data online or offline"],
|
online: Annotated[bool, "to fetch data online or offline"],
|
||||||
) -> str:
|
) -> str:
|
||||||
|
|
||||||
curr_date = datetime.strptime(curr_date, "%Y-%m-%d")
|
curr_date_dt = datetime.strptime(curr_date, "%Y-%m-%d")
|
||||||
curr_date = curr_date.strftime("%Y-%m-%d")
|
curr_date_str = curr_date_dt.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
indicator_value = StockstatsUtils.get_stock_stats(
|
indicator_value = StockstatsUtils.get_stock_stats(
|
||||||
symbol,
|
symbol,
|
||||||
indicator,
|
indicator,
|
||||||
curr_date,
|
curr_date_str,
|
||||||
os.path.join(DATA_DIR, "market_data", "price_data"),
|
os.path.join(DATA_DIR, "market_data", "price_data"),
|
||||||
online=online,
|
online=online,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(
|
print(
|
||||||
f"Error getting stockstats indicator data for indicator {indicator} on {curr_date}: {e}"
|
f"Error getting stockstats indicator data for indicator {indicator} on {curr_date_str}: {e}"
|
||||||
)
|
)
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
@ -591,9 +599,7 @@ def get_YFin_data_window(
|
||||||
look_back_days: Annotated[int, "how many days to look back"],
|
look_back_days: Annotated[int, "how many days to look back"],
|
||||||
) -> str:
|
) -> str:
|
||||||
# calculate past days
|
# calculate past days
|
||||||
date_obj = datetime.strptime(curr_date, "%Y-%m-%d")
|
start_date, _ = parse_date_range(curr_date, look_back_days)
|
||||||
before = date_obj - relativedelta(days=look_back_days)
|
|
||||||
start_date = before.strftime("%Y-%m-%d")
|
|
||||||
|
|
||||||
# read in data
|
# read in data
|
||||||
data = pd.read_csv(
|
data = pd.read_csv(
|
||||||
|
|
@ -703,9 +709,13 @@ def get_YFin_data(
|
||||||
return filtered_data
|
return filtered_data
|
||||||
|
|
||||||
|
|
||||||
|
# Enhanced search provider factory instance (singleton)
|
||||||
|
_search_factory = create_search_provider_factory()
|
||||||
|
|
||||||
|
|
||||||
def get_stock_news(ticker, curr_date):
|
def get_stock_news(ticker, curr_date):
|
||||||
config = get_config()
|
config = get_config()
|
||||||
search_provider = SearchProviderFactory.create_provider(config)
|
search_provider = _search_factory.create_provider(config)
|
||||||
query = f"Can you search Social Media for {ticker} from 7 days before {curr_date} to {curr_date}? Make sure you only get the data posted during that period."
|
query = f"Can you search Social Media for {ticker} from 7 days before {curr_date} to {curr_date}? Make sure you only get the data posted during that period."
|
||||||
return search_provider.search(query)
|
return search_provider.search(query)
|
||||||
|
|
||||||
|
|
@ -713,7 +723,7 @@ def get_stock_news(ticker, curr_date):
|
||||||
|
|
||||||
def get_global_news(curr_date):
|
def get_global_news(curr_date):
|
||||||
config = get_config()
|
config = get_config()
|
||||||
search_provider = SearchProviderFactory.create_provider(config)
|
search_provider = _search_factory.create_provider(config)
|
||||||
query = f"Search for global macroeconomic news and financial market updates from 7 days before {curr_date} to {curr_date}. Focus on central bank decisions, economic indicators, geopolitical events, and market-moving news that would be important for trading decisions."
|
query = f"Search for global macroeconomic news and financial market updates from 7 days before {curr_date} to {curr_date}. Focus on central bank decisions, economic indicators, geopolitical events, and market-moving news that would be important for trading decisions."
|
||||||
return search_provider.search(query)
|
return search_provider.search(query)
|
||||||
|
|
||||||
|
|
@ -721,7 +731,7 @@ def get_global_news(curr_date):
|
||||||
|
|
||||||
def get_fundamentals(ticker, curr_date):
|
def get_fundamentals(ticker, curr_date):
|
||||||
config = get_config()
|
config = get_config()
|
||||||
search_provider = SearchProviderFactory.create_provider(config)
|
search_provider = _search_factory.create_provider(config)
|
||||||
query = f"Search for fundamental analysis data and financial metrics for {ticker} stock from the month before {curr_date} to the month of {curr_date}. Look for earnings reports, financial ratios like PE, PS, cash flow, revenue growth, analyst ratings, and any fundamental analysis discussions. Please present key metrics in a structured format."
|
query = f"Search for fundamental analysis data and financial metrics for {ticker} stock from the month before {curr_date} to the month of {curr_date}. Look for earnings reports, financial ratios like PE, PS, cash flow, revenue growth, analyst ratings, and any fundamental analysis discussions. Please present key metrics in a structured format."
|
||||||
return search_provider.search(query)
|
return search_provider.search(query)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from abc import ABC, abstractmethod
|
||||||
|
|
||||||
class SearchProvider(ABC):
|
class SearchProvider(ABC):
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def search(self, query: str, ticker: str, curr_date: str) -> str:
|
def search(self, query: str) -> str:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,133 @@
|
||||||
from .search_provider import (
|
from .search_provider import SearchProvider
|
||||||
SearchProvider,
|
|
||||||
GoogleSearchProvider,
|
|
||||||
OpenAISearchProvider
|
|
||||||
)
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
from typing import Dict, Callable, Any
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
|
||||||
class SearchProviderFactory:
|
class ProviderSelector(ABC):
|
||||||
_cache = {} # 클래스 레벨 캐시
|
"""Abstract base class for provider selection strategies."""
|
||||||
|
|
||||||
@staticmethod
|
@abstractmethod
|
||||||
def create_provider(config: dict[str, any]) -> SearchProvider:
|
def select_provider_type(self, config: Dict[str, Any]) -> str:
|
||||||
|
"""Select provider type based on configuration."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MappingBasedProviderSelector(ProviderSelector):
|
||||||
|
"""Selects provider based on URL pattern mapping table."""
|
||||||
|
|
||||||
|
def __init__(self, mappings: Dict[str, str], default_provider: str = "openai"):
|
||||||
|
self._mappings = mappings
|
||||||
|
self._default_provider = default_provider
|
||||||
|
|
||||||
|
def select_provider_type(self, config: Dict[str, Any]) -> str:
|
||||||
|
backend_url = config.get("backend_url", "")
|
||||||
|
for pattern, provider_type in self._mappings.items():
|
||||||
|
if pattern in backend_url:
|
||||||
|
return provider_type
|
||||||
|
return self._default_provider
|
||||||
|
|
||||||
|
|
||||||
|
class SearchProviderRegistry:
|
||||||
|
"""Registry for search provider creation functions."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._providers: Dict[str, Callable[[Dict[str, Any]], SearchProvider]] = {}
|
||||||
|
|
||||||
|
def register(self, provider_type: str, creator: Callable[[Dict[str, Any]], SearchProvider]):
|
||||||
|
"""Register a provider creator function."""
|
||||||
|
self._providers[provider_type] = creator
|
||||||
|
|
||||||
|
def create(self, provider_type: str, config: Dict[str, Any]) -> SearchProvider:
|
||||||
|
"""Create a provider instance using registered creator."""
|
||||||
|
if provider_type not in self._providers:
|
||||||
|
raise ValueError(f"Unknown provider type: {provider_type}")
|
||||||
|
return self._providers[provider_type](config)
|
||||||
|
|
||||||
|
def get_available_types(self) -> list[str]:
|
||||||
|
"""Get list of available provider types."""
|
||||||
|
return list(self._providers.keys())
|
||||||
|
|
||||||
|
|
||||||
|
class SearchProviderFactoryImpl:
|
||||||
|
"""Enhanced factory for creating SearchProvider instances with caching and extensibility."""
|
||||||
|
|
||||||
|
def __init__(self, registry: SearchProviderRegistry, selector: ProviderSelector):
|
||||||
|
self._registry = registry
|
||||||
|
self._selector = selector
|
||||||
|
self._cache: Dict[str, SearchProvider] = {}
|
||||||
|
|
||||||
|
def create_provider(self, config: Dict[str, Any]) -> SearchProvider:
|
||||||
"""
|
"""
|
||||||
Create a SearchProvider with caching to avoid creating new instances.
|
Create a SearchProvider with caching to avoid creating new instances.
|
||||||
Uses config hash as cache key for efficient reuse.
|
Uses config hash as cache key for efficient reuse.
|
||||||
"""
|
"""
|
||||||
# Create cache key from relevant config values
|
# Create cache key from relevant config values
|
||||||
cache_key_data = {
|
cache_key_data = {
|
||||||
"backend_url": config["backend_url"],
|
"backend_url": config.get("backend_url", ""),
|
||||||
"model": config["quick_think_llm"]
|
"model": config.get("quick_think_llm", "")
|
||||||
}
|
}
|
||||||
cache_key = hashlib.md5(json.dumps(cache_key_data, sort_keys=True).encode()).hexdigest()
|
cache_key = hashlib.md5(json.dumps(cache_key_data, sort_keys=True).encode()).hexdigest()
|
||||||
|
|
||||||
# Return cached instance if exists
|
# Return cached instance if exists
|
||||||
if cache_key in SearchProviderFactory._cache:
|
if cache_key in self._cache:
|
||||||
return SearchProviderFactory._cache[cache_key]
|
return self._cache[cache_key]
|
||||||
|
|
||||||
# Create new instance
|
# Select and create provider
|
||||||
backend_url = config["backend_url"]
|
provider_type = self._selector.select_provider_type(config)
|
||||||
model = config["quick_think_llm"]
|
provider = self._registry.create(provider_type, config)
|
||||||
|
|
||||||
if "generativelanguage.googleapis.com" in backend_url:
|
|
||||||
provider = GoogleSearchProvider(model)
|
|
||||||
else:
|
|
||||||
provider = OpenAISearchProvider(model, backend_url)
|
|
||||||
|
|
||||||
# Cache and return
|
# Cache and return
|
||||||
SearchProviderFactory._cache[cache_key] = provider
|
self._cache[cache_key] = provider
|
||||||
return provider
|
return provider
|
||||||
|
|
||||||
|
def clear_cache(self):
|
||||||
|
"""Clear the provider cache (useful for testing or config changes)."""
|
||||||
|
self._cache.clear()
|
||||||
|
|
||||||
|
def get_available_provider_types(self) -> list[str]:
|
||||||
|
"""Get list of available provider types."""
|
||||||
|
return self._registry.get_available_types()
|
||||||
|
|
||||||
|
|
||||||
|
def create_search_provider_factory() -> SearchProviderFactoryImpl:
|
||||||
|
"""Create a configured SearchProviderFactory with default providers."""
|
||||||
|
registry = SearchProviderRegistry()
|
||||||
|
|
||||||
|
# Register default providers
|
||||||
|
def create_google_provider(config: Dict[str, Any]) -> SearchProvider:
|
||||||
|
from .search_provider import GoogleSearchProvider
|
||||||
|
return GoogleSearchProvider(config["quick_think_llm"])
|
||||||
|
|
||||||
|
def create_openai_provider(config: Dict[str, Any]) -> SearchProvider:
|
||||||
|
from .search_provider import OpenAISearchProvider
|
||||||
|
return OpenAISearchProvider(config["quick_think_llm"], config["backend_url"])
|
||||||
|
|
||||||
|
registry.register("google", create_google_provider)
|
||||||
|
registry.register("openai", create_openai_provider)
|
||||||
|
|
||||||
|
# Create URL pattern mappings (easily extensible)
|
||||||
|
url_mappings = {
|
||||||
|
"generativelanguage.googleapis.com": "google",
|
||||||
|
"api.openai.com": "openai",
|
||||||
|
}
|
||||||
|
|
||||||
|
selector = MappingBasedProviderSelector(url_mappings, default_provider="openai")
|
||||||
|
return SearchProviderFactoryImpl(registry, selector)
|
||||||
|
|
||||||
|
|
||||||
|
# Backward compatibility - singleton instance
|
||||||
|
_default_factory = create_search_provider_factory()
|
||||||
|
|
||||||
|
|
||||||
|
class SearchProviderFactory:
|
||||||
|
"""Backward compatibility wrapper for the old static factory."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_provider(config: Dict[str, Any]) -> SearchProvider:
|
||||||
|
return _default_factory.create_provider(config)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def clear_cache():
|
def clear_cache():
|
||||||
"""Clear the provider cache (useful for testing or config changes)."""
|
_default_factory.clear_cache()
|
||||||
SearchProviderFactory._cache.clear()
|
|
||||||
|
|
||||||
|
|
@ -3,7 +3,7 @@ import os
|
||||||
DEFAULT_CONFIG = {
|
DEFAULT_CONFIG = {
|
||||||
"project_dir": os.path.abspath(os.path.join(os.path.dirname(__file__), ".")),
|
"project_dir": os.path.abspath(os.path.join(os.path.dirname(__file__), ".")),
|
||||||
"results_dir": os.getenv("TRADINGAGENTS_RESULTS_DIR", "./results"),
|
"results_dir": os.getenv("TRADINGAGENTS_RESULTS_DIR", "./results"),
|
||||||
"data_dir": "/Users/yluo/Documents/Code/ScAI/FR1-data",
|
"data_dir": os.getenv("TRADINGAGENTS_DATA_DIR", "./data"),
|
||||||
"data_cache_dir": os.path.join(
|
"data_cache_dir": os.path.join(
|
||||||
os.path.abspath(os.path.join(os.path.dirname(__file__), ".")),
|
os.path.abspath(os.path.join(os.path.dirname(__file__), ".")),
|
||||||
"dataflows/data_cache",
|
"dataflows/data_cache",
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ class TradingAgentsGraph:
|
||||||
# online tools
|
# online tools
|
||||||
self.toolkit.get_stock_news,
|
self.toolkit.get_stock_news,
|
||||||
# offline tools
|
# offline tools
|
||||||
self.toolkit.get_reddit_stock_info,
|
# self.toolkit.get_reddit_stock_info,
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
"news": ToolNode(
|
"news": ToolNode(
|
||||||
|
|
@ -136,8 +136,8 @@ class TradingAgentsGraph:
|
||||||
self.toolkit.get_global_news,
|
self.toolkit.get_global_news,
|
||||||
self.toolkit.get_google_news,
|
self.toolkit.get_google_news,
|
||||||
# offline tools
|
# offline tools
|
||||||
self.toolkit.get_finnhub_news,
|
# self.toolkit.get_finnhub_news,
|
||||||
self.toolkit.get_reddit_news,
|
# self.toolkit.get_reddit_news,
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
"fundamentals": ToolNode(
|
"fundamentals": ToolNode(
|
||||||
|
|
@ -145,11 +145,11 @@ class TradingAgentsGraph:
|
||||||
# online tools
|
# online tools
|
||||||
self.toolkit.get_fundamentals,
|
self.toolkit.get_fundamentals,
|
||||||
# offline tools
|
# offline tools
|
||||||
self.toolkit.get_finnhub_company_insider_sentiment,
|
# self.toolkit.get_finnhub_company_insider_sentiment,
|
||||||
self.toolkit.get_finnhub_company_insider_transactions,
|
# self.toolkit.get_finnhub_company_insider_transactions,
|
||||||
self.toolkit.get_simfin_balance_sheet,
|
# self.toolkit.get_simfin_balance_sheet,
|
||||||
self.toolkit.get_simfin_cashflow,
|
# self.toolkit.get_simfin_cashflow,
|
||||||
self.toolkit.get_simfin_income_stmt,
|
# self.toolkit.get_simfin_income_stmt,
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue