mirror of
https://github.com/norandom/trading_analysis.git
synced 2026-09-28 19:29:27 +00:00
165 KiB
165 KiB
In [1]:
import pandas as pd
import cot_reports as cot # Ensure cot_reports is correctly imported and cot.cot_year() works as expected
df = pd.DataFrame()
begin_year = 2020
end_year = 2024
for i in range(begin_year, end_year + 1):
# Assuming cot.cot_year returns a DataFrame
single_year = pd.DataFrame(cot.cot_year(i, cot_report_type='disaggregated_fut'))
single_year.to_csv(f'./COT_CFTC_{i}.csv', index=False)Selected: disaggregated_fut Downloaded single year data from: 2020 Stored the file f_year.txt in the working directory. Selected: disaggregated_fut Downloaded single year data from: 2021 Stored the file f_year.txt in the working directory. Selected: disaggregated_fut Downloaded single year data from: 2022 Stored the file f_year.txt in the working directory. Selected: disaggregated_fut Downloaded single year data from: 2023 Stored the file f_year.txt in the working directory. Selected: disaggregated_fut Downloaded single year data from: 2024 Stored the file f_year.txt in the working directory.
In [2]:
import glob
# Adjust the path and pattern according to your CSV files location and naming convention
csv_files = glob.glob('COT_CFTC_20*.csv')
print(csv_files)['COT_CFTC_2022.csv', 'COT_CFTC_2023.csv', 'COT_CFTC_2021.csv', 'COT_CFTC_2020.csv', 'COT_CFTC_2024.csv']
In [3]:
df = pd.read_csv('COT_CFTC_2024.csv')/tmp/ipykernel_1629470/490941526.py:1: DtypeWarning: Columns (120,121,132,133,134,135,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160) have mixed types. Specify dtype option on import or set low_memory=False.
df = pd.read_csv('COT_CFTC_2024.csv')
In [4]:
import pandas as pd
df["Report_Date_as_YYYY-MM-DD"] = pd.to_datetime(df["Report_Date_as_YYYY-MM-DD"], format='%Y-%m-%d')
df.set_index("Report_Date_as_YYYY-MM-DD")
df.shapeOut [4]:
(8344, 191)
In [5]:
!cat COT_CFTC_2024.csv | wc -l8345
In [6]:
df.head()Out [6]:
| Market_and_Exchange_Names | As_of_Date_In_Form_YYMMDD | Report_Date_as_YYYY-MM-DD | CFTC_Contract_Market_Code | CFTC_Market_Code | CFTC_Region_Code | CFTC_Commodity_Code | Open_Interest_All | Prod_Merc_Positions_Long_All | Prod_Merc_Positions_Short_All | ... | Conc_Net_LE_4_TDR_Long_Other | Conc_Net_LE_4_TDR_Short_Other | Conc_Net_LE_8_TDR_Long_Other | Conc_Net_LE_8_TDR_Short_Other | Contract_Units | CFTC_Contract_Market_Code_Quotes | CFTC_Market_Code_Quotes | CFTC_Commodity_Code_Quotes | CFTC_SubGroup_Code | FutOnly_or_Combined | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | WHEAT-SRW - CHICAGO BOARD OF TRADE | 240813 | 2024-08-13 | 001602 | CBT | 0 | 1 | 401604 | 68899 | 85867 | ... | 39.0 | 31.7 | 54.2 | 42.6 | (CONTRACTS OF 5,000 BUSHELS) | 001602 | CBT | 1 | A10 | FutOnly |
| 1 | WHEAT-SRW - CHICAGO BOARD OF TRADE | 240806 | 2024-08-06 | 001602 | CBT | 0 | 1 | 431547 | 73401 | 85750 | ... | 41.6 | 32.3 | 57.3 | 41.7 | (CONTRACTS OF 5,000 BUSHELS) | 001602 | CBT | 1 | A10 | FutOnly |
| 2 | WHEAT-SRW - CHICAGO BOARD OF TRADE | 240730 | 2024-07-30 | 001602 | CBT | 0 | 1 | 432863 | 73086 | 83875 | ... | 46.0 | 28.5 | 60.8 | 38.4 | (CONTRACTS OF 5,000 BUSHELS) | 001602 | CBT | 1 | A10 | FutOnly |
| 3 | WHEAT-SRW - CHICAGO BOARD OF TRADE | 240723 | 2024-07-23 | 001602 | CBT | 0 | 1 | 421227 | 63636 | 81374 | ... | 48.3 | 27.9 | 63.5 | 37.7 | (CONTRACTS OF 5,000 BUSHELS) | 001602 | CBT | 1 | A10 | FutOnly |
| 4 | WHEAT-SRW - CHICAGO BOARD OF TRADE | 240716 | 2024-07-16 | 001602 | CBT | 0 | 1 | 413885 | 64297 | 81558 | ... | 50.4 | 28.0 | 65.9 | 37.3 | (CONTRACTS OF 5,000 BUSHELS) | 001602 | CBT | 1 | A10 | FutOnly |
5 rows × 191 columns
In [8]:
import pandas as pd
# Filter for rows where "Market_and_Exchange_Names" matches either of the specified values
silver_df = df[df["Market_and_Exchange_Names"].isin(["SILVER - COMMODITY EXCHANGE INC."])].copy()
# After filtering, you can standardize the "Market_and_Exchange_Names" if you want all of them to have the same name
# This is optional and based on your specific requirement to 'merge' under a unified label
silver_df["Market_and_Exchange_Names"] = "COPPER-GRADE #1 - COMMODITY EXCHANGE INC."
silver_df["Report_Date_as_YYYY-MM-DD"] = pd.to_datetime(df["Report_Date_as_YYYY-MM-DD"], format='%Y-%m-%d')
silver_df = silver_df.set_index("Report_Date_as_YYYY-MM-DD")In [12]:
silver_df.shape # we have calendar week 33Out [12]:
(33, 190)
In [20]:
print(list(silver_df.columns))['Market_and_Exchange_Names', 'As_of_Date_In_Form_YYMMDD', 'CFTC_Contract_Market_Code', 'CFTC_Market_Code', 'CFTC_Region_Code', 'CFTC_Commodity_Code', 'Open_Interest_All', 'Prod_Merc_Positions_Long_All', 'Prod_Merc_Positions_Short_All', 'Swap_Positions_Long_All', 'Swap__Positions_Short_All', 'Swap__Positions_Spread_All', 'M_Money_Positions_Long_All', 'M_Money_Positions_Short_All', 'M_Money_Positions_Spread_All', 'Other_Rept_Positions_Long_All', 'Other_Rept_Positions_Short_All', 'Other_Rept_Positions_Spread_All', 'Tot_Rept_Positions_Long_All', 'Tot_Rept_Positions_Short_All', 'NonRept_Positions_Long_All', 'NonRept_Positions_Short_All', 'Open_Interest_Old', 'Prod_Merc_Positions_Long_Old', 'Prod_Merc_Positions_Short_Old', 'Swap_Positions_Long_Old', 'Swap__Positions_Short_Old', 'Swap__Positions_Spread_Old', 'M_Money_Positions_Long_Old', 'M_Money_Positions_Short_Old', 'M_Money_Positions_Spread_Old', 'Other_Rept_Positions_Long_Old', 'Other_Rept_Positions_Short_Old', 'Other_Rept_Positions_Spread_Old', 'Tot_Rept_Positions_Long_Old', 'Tot_Rept_Positions_Short_Old', 'NonRept_Positions_Long_Old', 'NonRept_Positions_Short_Old', 'Open_Interest_Other', 'Prod_Merc_Positions_Long_Other', 'Prod_Merc_Positions_Short_Other', 'Swap_Positions_Long_Other', 'Swap__Positions_Short_Other', 'Swap__Positions_Spread_Other', 'M_Money_Positions_Long_Other', 'M_Money_Positions_Short_Other', 'M_Money_Positions_Spread_Other', 'Other_Rept_Positions_Long_Other', 'Other_Rept_Positions_Short_Other', 'Other_Rept_Positions_Spread_Other', 'Tot_Rept_Positions_Long_Other', 'Tot_Rept_Positions_Short_Other', 'NonRept_Positions_Long_Other', 'NonRept_Positions_Short_Other', 'Change_in_Open_Interest_All', 'Change_in_Prod_Merc_Long_All', 'Change_in_Prod_Merc_Short_All', 'Change_in_Swap_Long_All', 'Change_in_Swap_Short_All', 'Change_in_Swap_Spread_All', 'Change_in_M_Money_Long_All', 'Change_in_M_Money_Short_All', 'Change_in_M_Money_Spread_All', 'Change_in_Other_Rept_Long_All', 'Change_in_Other_Rept_Short_All', 'Change_in_Other_Rept_Spread_All', 'Change_in_Tot_Rept_Long_All', 'Change_in_Tot_Rept_Short_All', 'Change_in_NonRept_Long_All', 'Change_in_NonRept_Short_All', 'Pct_of_Open_Interest_All', 'Pct_of_OI_Prod_Merc_Long_All', 'Pct_of_OI_Prod_Merc_Short_All', 'Pct_of_OI_Swap_Long_All', 'Pct_of_OI_Swap_Short_All', 'Pct_of_OI_Swap_Spread_All', 'Pct_of_OI_M_Money_Long_All', 'Pct_of_OI_M_Money_Short_All', 'Pct_of_OI_M_Money_Spread_All', 'Pct_of_OI_Other_Rept_Long_All', 'Pct_of_OI_Other_Rept_Short_All', 'Pct_of_OI_Other_Rept_Spread_All', 'Pct_of_OI_Tot_Rept_Long_All', 'Pct_of_OI_Tot_Rept_Short_All', 'Pct_of_OI_NonRept_Long_All', 'Pct_of_OI_NonRept_Short_All', 'Pct_of_Open_Interest_Old', 'Pct_of_OI_Prod_Merc_Long_Old', 'Pct_of_OI_Prod_Merc_Short_Old', 'Pct_of_OI_Swap_Long_Old', 'Pct_of_OI_Swap_Short_Old', 'Pct_of_OI_Swap_Spread_Old', 'Pct_of_OI_M_Money_Long_Old', 'Pct_of_OI_M_Money_Short_Old', 'Pct_of_OI_M_Money_Spread_Old', 'Pct_of_OI_Other_Rept_Long_Old', 'Pct_of_OI_Other_Rept_Short_Old', 'Pct_of_OI_Other_Rept_Spread_Old', 'Pct_of_OI_Tot_Rept_Long_Old', 'Pct_of_OI_Tot_Rept_Short_Old', 'Pct_of_OI_NonRept_Long_Old', 'Pct_of_OI_NonRept_Short_Old', 'Pct_of_Open_Interest_Other', 'Pct_of_OI_Prod_Merc_Long_Other', 'Pct_of_OI_Prod_Merc_Short_Other', 'Pct_of_OI_Swap_Long_Other', 'Pct_of_OI_Swap_Short_Other', 'Pct_of_OI_Swap_Spread_Other', 'Pct_of_OI_M_Money_Long_Other', 'Pct_of_OI_M_Money_Short_Other', 'Pct_of_OI_M_Money_Spread_Other', 'Pct_of_OI_Other_Rept_Long_Other', 'Pct_of_OI_Other_Rept_Short_Other', 'Pct_of_OI_Other_Rept_Spread_Other', 'Pct_of_OI_Tot_Rept_Long_Other', 'Pct_of_OI_Tot_Rept_Short_Other', 'Pct_of_OI_NonRept_Long_Other', 'Pct_of_OI_NonRept_Short_Other', 'Traders_Tot_All', 'Traders_Prod_Merc_Long_All', 'Traders_Prod_Merc_Short_All', 'Traders_Swap_Long_All', 'Traders_Swap_Short_All', 'Traders_Swap_Spread_All', 'Traders_M_Money_Long_All', 'Traders_M_Money_Short_All', 'Traders_M_Money_Spread_All', 'Traders_Other_Rept_Long_All', 'Traders_Other_Rept_Short_All', 'Traders_Other_Rept_Spread_All', 'Traders_Tot_Rept_Long_All', 'Traders_Tot_Rept_Short_All', 'Traders_Tot_Old', 'Traders_Prod_Merc_Long_Old', 'Traders_Prod_Merc_Short_Old', 'Traders_Swap_Long_Old', 'Traders_Swap_Short_Old', 'Traders_Swap_Spread_Old', 'Traders_M_Money_Long_Old', 'Traders_M_Money_Short_Old', 'Traders_M_Money_Spread_Old', 'Traders_Other_Rept_Long_Old', 'Traders_Other_Rept_Short_Old', 'Traders_Other_Rept_Spread_Old', 'Traders_Tot_Rept_Long_Old', 'Traders_Tot_Rept_Short_Old', 'Traders_Tot_Other', 'Traders_Prod_Merc_Long_Other', 'Traders_Prod_Merc_Short_Other', 'Traders_Swap_Long_Other', 'Traders_Swap_Short_Other', 'Traders_Swap_Spread_Other', 'Traders_M_Money_Long_Other', 'Traders_M_Money_Short_Other', 'Traders_M_Money_Spread_Other', 'Traders_Other_Rept_Long_Other', 'Traders_Other_Rept_Short_Other', 'Traders_Other_Rept_Spread_Other', 'Traders_Tot_Rept_Long_Other', 'Traders_Tot_Rept_Short_Other', 'Conc_Gross_LE_4_TDR_Long_All', 'Conc_Gross_LE_4_TDR_Short_All', 'Conc_Gross_LE_8_TDR_Long_All', 'Conc_Gross_LE_8_TDR_Short_All', 'Conc_Net_LE_4_TDR_Long_All', 'Conc_Net_LE_4_TDR_Short_All', 'Conc_Net_LE_8_TDR_Long_All', 'Conc_Net_LE_8_TDR_Short_All', 'Conc_Gross_LE_4_TDR_Long_Old', 'Conc_Gross_LE_4_TDR_Short_Old', 'Conc_Gross_LE_8_TDR_Long_Old', 'Conc_Gross_LE_8_TDR_Short_Old', 'Conc_Net_LE_4_TDR_Long_Old', 'Conc_Net_LE_4_TDR_Short_Old', 'Conc_Net_LE_8_TDR_Long_Old', 'Conc_Net_LE_8_TDR_Short_Old', 'Conc_Gross_LE_4_TDR_Long_Other', 'Conc_Gross_LE_4_TDR_Short_Other', 'Conc_Gross_LE_8_TDR_Long_Other', 'Conc_Gross_LE_8_TDR_Short_Other', 'Conc_Net_LE_4_TDR_Long_Other', 'Conc_Net_LE_4_TDR_Short_Other', 'Conc_Net_LE_8_TDR_Long_Other', 'Conc_Net_LE_8_TDR_Short_Other', 'Contract_Units', 'CFTC_Contract_Market_Code_Quotes', 'CFTC_Market_Code_Quotes', 'CFTC_Commodity_Code_Quotes', 'CFTC_SubGroup_Code', 'FutOnly_or_Combined']
In [14]:
open_interest_pct_old_columns = [col for col in df.columns if 'pct' in col.lower() and col.endswith('_Old')]
open_interest_pct_old_columnsOut [14]:
['Pct_of_Open_Interest_Old', 'Pct_of_OI_Prod_Merc_Long_Old', 'Pct_of_OI_Prod_Merc_Short_Old', 'Pct_of_OI_Swap_Long_Old', 'Pct_of_OI_Swap_Short_Old', 'Pct_of_OI_Swap_Spread_Old', 'Pct_of_OI_M_Money_Long_Old', 'Pct_of_OI_M_Money_Short_Old', 'Pct_of_OI_M_Money_Spread_Old', 'Pct_of_OI_Other_Rept_Long_Old', 'Pct_of_OI_Other_Rept_Short_Old', 'Pct_of_OI_Other_Rept_Spread_Old', 'Pct_of_OI_Tot_Rept_Long_Old', 'Pct_of_OI_Tot_Rept_Short_Old', 'Pct_of_OI_NonRept_Long_Old', 'Pct_of_OI_NonRept_Short_Old']
In [21]:
needed_columns = ["Open_Interest_All", "Pct_of_OI_Prod_Merc_Long_Old", "Pct_of_OI_Prod_Merc_Short_Old"]In [22]:
filtered_silver_df = silver_df[needed_columns].copy()
filtered_silver_df.head()Out [22]:
| Open_Interest_All | Pct_of_OI_Prod_Merc_Long_Old | Pct_of_OI_Prod_Merc_Short_Old | |
|---|---|---|---|
| Report_Date_as_YYYY-MM-DD | |||
| 2024-08-13 | 147859 | 3.1 | 25.3 |
| 2024-08-06 | 147537 | 3.0 | 25.4 |
| 2024-07-30 | 151437 | 2.7 | 25.4 |
| 2024-07-23 | 157106 | 2.2 | 25.8 |
| 2024-07-16 | 166641 | 1.7 | 26.0 |
In [ ]:
In [29]:
import pandas as pd
import plotly.graph_objects as go
import numpy as np
from scipy import signal
# Assuming df is your DataFrame with the COT data
# If not, you'll need to load your data here
# Create the main figure
fig = go.Figure()
# Add trace for Open Interest
fig.add_trace(go.Scatter(
x=filtered_silver_df.index,
y=filtered_silver_df['Open_Interest_All'],
mode='lines',
name='Open Interest',
line=dict(width=2, color='blue')
))
# Update layout
fig.update_layout(
title='COT Data: Open Interest Over Time (Silver)',
yaxis_title='Open Interest',
xaxis_title='Date',
height=600,
width=800,
hovermode='x unified'
)
# Improve date labeling for better readability
fig.update_xaxes(
tickformat="%d %b %Y",
tickangle=45,
dtick="M1",
ticklabelmode="period"
)
# Show the plot
fig.show()
# Calculate and print metrics
print("\nMetrics for Open Interest:")
data = filtered_silver_df['Open_Interest_All']
print(f"Volatility (Standard Deviation): {data.std():.2f}")
print(f"Average: {data.mean():.2f}")
print(f"Median: {data.median():.2f}")
print(f"Minimum: {data.min():.2f}")
print(f"Maximum: {data.max():.2f}")
# Calculate typical range
typical_low = np.percentile(data, 25)
typical_high = np.percentile(data, 75)
print(f"Typical Range: {typical_low:.2f} to {typical_high:.2f}")
# Identify trends
def identify_trend(series):
# Calculate the overall trend
trend = np.polyfit(range(len(series)), series, 1)[0]
if trend > 0:
return "Upward"
elif trend < 0:
return "Downward"
else:
return "Stable"
trend = identify_trend(data)
print(f"\nOverall trend: {trend}")
# Identify significant points
def find_peaks(series, prominence=1000):
peaks, _ = signal.find_peaks(series, prominence=prominence)
troughs, _ = signal.find_peaks(-series, prominence=prominence)
return peaks, troughs
peaks, troughs = find_peaks(data)
print("\nSignificant points:")
for peak in peaks:
print(f"Peak on {df.index[peak]}: {data.iloc[peak]:.2f}")
for trough in troughs:
print(f"Trough on {df.index[trough]}: {data.iloc[trough]:.2f}")
# Identify sudden changes
pct_change = data.pct_change()
sudden_changes = pct_change[abs(pct_change) > 0.05] # 5% threshold
if not sudden_changes.empty:
print("\nSudden changes (>5% day-to-day):")
for date, change in sudden_changes.items():
print(f"{date}: {change*100:.2f}% change")
else:
print("\nNo sudden changes above 5% threshold detected.")Metrics for Open Interest: Volatility (Standard Deviation): 15889.35 Average: 158040.03 Median: 157106.00 Minimum: 131956.00 Maximum: 186945.00 Typical Range: 146584.00 to 171371.00 Overall trend: Downward Significant points: Peak on 4: 166641.00 Peak on 12: 186945.00 Peak on 17: 175784.00 Peak on 26: 152544.00 Peak on 29: 138617.00 Trough on 6: 154724.00 Trough on 14: 161868.00 Trough on 23: 141026.00 Trough on 28: 136544.00 Trough on 30: 131956.00 Sudden changes (>5% day-to-day): 2024-07-16 00:00:00: 6.07% change 2024-07-02 00:00:00: -5.22% change 2024-06-25 00:00:00: 7.59% change 2024-06-18 00:00:00: 6.09% change 2024-05-14 00:00:00: -8.33% change 2024-05-07 00:00:00: -5.55% change 2024-04-23 00:00:00: 5.67% change 2024-03-12 00:00:00: -5.63% change 2024-01-30 00:00:00: -7.32% change
In [ ]:
In [31]:
import pandas as pd
def export_to_amibroker_csv(df, output_file='amibroker_data.csv'):
# Create a copy of the DataFrame to avoid modifying the original
export_df = df.copy()
# Reset the index to make the date a column
export_df = export_df.reset_index()
# Rename columns to match AmiBroker format
export_df['Date'] = pd.to_datetime(export_df['Report_Date_as_YYYY-MM-DD'])
export_df['Close'] = export_df['Open_Interest_All']
export_df['Volume'] = export_df['Pct_of_OI_Prod_Merc_Long_Old']
# Create Open, High, Low columns with the same value as Close
export_df['Open'] = export_df['Close']
export_df['High'] = export_df['Close']
export_df['Low'] = export_df['Close']
# Select and order columns for AmiBroker
amibroker_df = export_df[['Date', 'Open', 'High', 'Low', 'Close', 'Volume']]
# Sort by date in descending order (most recent first)
amibroker_df = amibroker_df.sort_values('Date', ascending=False)
# Export to CSV
amibroker_df.to_csv(output_file, index=False, date_format='%Y-%m-%d')
print(f"Data exported to {output_file}")
# Usage
export_to_amibroker_csv(filtered_silver_df, 'silver_data_for_amibroker.csv')Data exported to silver_data_for_amibroker.csv
In [ ]: