{ "cells": [ { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "ename": "ModuleNotFoundError", "evalue": "No module named 'tushare'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[3], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mtushare\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mts\u001b[39;00m\n\u001b[0;32m 2\u001b[0m ts\u001b[38;5;241m.\u001b[39mset_token(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m78282dabb315ee578fb73a9b328f493026e97d5af709acb331b7b348\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m 3\u001b[0m pro \u001b[38;5;241m=\u001b[39m ts\u001b[38;5;241m.\u001b[39mpro_api()\n", "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'tushare'" ] } ], "source": [ "import tushare as ts\n", "ts.set_token('78282dabb315ee578fb73a9b328f493026e97d5af709acb331b7b348')\n", "pro = ts.pro_api()" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "300\n", "\n", "0.15\n", "\n" ] } ], "source": [ "from datetime import datetime, timedelta\n", "import pandas as pd\n", "fees_df = pd.read_csv('./futures_fees_info.csv', usecols= [1, 4, 17, 19, 25],names=['合约', '合约乘数', '做多保证金率', '做空保证金率', '品种代码'])\n", "data0 = int(fees_df[fees_df['合约'] == 'IH2407']['合约乘数'].iloc[0])\n", "\n", "print(data0)\n", "print(type(data0))\n", "data1 = float(fees_df[fees_df['合约'] == 'IH2407']['做多保证金率'].iloc[0])\n", "print(data1)\n", "print(type(data1))\n", "# fees_df[fees_df['合约'] == 'IH2407']['做空保证金率'].iloc[0]\n", "# (fees_df[fees_df['合约'] == 'IH2407']['做多保证金率'].iloc[0] + fees_df[fees_df['合约'] == 'IH2407']['做空保证金率'].iloc[0])/2" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "from datetime import datetime, timedelta\n", "import pandas as pd\n", "fees_df = pd.read_csv('./futures_fees_info.csv', usecols= [1, 4, 17, 19],names=['合约', '合约乘数', '做多保证金率', '做空保证金率'])\n", "contacts_df = pd.read_csv('./main_contacts.csv', usecols= [16, 17],names=['主连代码', '品种代码'])\n", "\n", "def get_main_contact_on_time(main_symbol_code):\n", " data_str = ''\n", " alpha_chars = ''\n", " numeric_chars = ''\n", " main_code = ''\n", "\n", " # main_symbol = pro.fut_mapping(ts_code=main_symbol_code, trade_date = data_str).loc[0,'mapping_ts_code'].split('.')[0]\n", " # exchange_id = pro.fut_mapping(ts_code=main_symbol_code, trade_date = data_str).loc[0,'mapping_ts_code'].split('.')[1]\n", " main_symbol = contacts_df[contacts_df['品种代码'] == main_symbol_code]['主连代码'].iloc[0]\n", "\n", "\n", " # # 拆分主连合约代码为交易标识和交易所代码(交易市场)\n", " # main_symbol = pro.fut_mapping(ts_code=main_symbol_code, trade_date = data_str).loc[0,'mapping_ts_code'].split('.')[0]\n", " # exchange_id = pro.fut_mapping(ts_code=main_symbol_code, trade_date = data_str).loc[0,'mapping_ts_code'].split('.')[1]\n", "\n", " # # 拆分交易标识中的合约产品代码和交割月份\n", " # for char in main_symbol:\n", " # if char.isalpha():\n", " # alpha_chars += char\n", " # elif char.isdigit():\n", " # numeric_chars += char\n", " \n", " # # 监理交易所映射\n", " # exchange = {'CFX': 'CFFEX', 'SHF':'SHFE', 'DCE':'DCE', 'GFE':'GFEX', 'INE':'INE', 'ZCE':'CZCE'}\n", "\n", " # # 计算per_unit:交易单位(每手)和转换后交易所识别的main_code:主连代码\n", " # if exchange_id == 'CFX' or exchange_id == 'SHF' or exchange_id == 'DCE' or exchange_id == 'GFE' or exchange_id == 'INE':\n", " # df = pro.fut_basic(exchange = exchange[exchange_id], fut_type='1', fut_code = alpha_chars, fields='ts_code,symbol,exchange,name,per_unit')\n", " # # ts_code = df[df['symbol'] == main_symbol]['ts_code'].iloc[0]\n", " # per_unit = df[df['symbol'] == main_symbol]['per_unit'].iloc[0]\n", "\n", " # # ds = pro.fut_settle(trade_date = data_str, ts_code =ts_code)\n", " # # ds['margin_rate'] = (ds['long_margin_rate'] + ds['short_margin_rate'])/2\n", " # # margin_rate = ds['margin_rate'].iloc[0]\n", " \n", " \n", " # if exchange_id == 'CFX':\n", " # main_code = main_symbol\n", " # elif exchange_id == 'SHF' or exchange_id == 'DCE' or exchange_id == 'GFE' or exchange_id == 'INE':\n", " # lower_alpha_chars = str.lower(alpha_chars) \n", " # main_code = lower_alpha_chars + numeric_chars\n", " # elif exchange_id == 'ZCE':\n", " # true_numeric_chars = numeric_chars[1:]\n", " # main_code = alpha_chars + true_numeric_chars \n", " # df = pro.fut_basic(exchange = exchange[exchange_id], fut_type='1', fut_code = alpha_chars, fields='ts_code,symbol,exchange,name,per_unit')\n", " # per_unit = df[df['symbol'] == main_code]['per_unit'].iloc[0]\n", " # main_code = alpha_chars + true_numeric_chars\n", "\n", " # print(\"最终使用的主连代码:\",main_code) \n", " # print(\"%s的交易单位(每手):%s\"%(main_symbol, per_unit))\n", " return main_symbol\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'IH2407'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "get_main_contact_on_time('IH')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from datetime import datetime, timedelta\n", "def get_main_contact_on_time(main_symbol_code):\n", " data_str = ''\n", " alpha_chars = ''\n", " numeric_chars = ''\n", " main_code = ''\n", "\n", " # 获取主连合约代码,如果是当天15点前日盘,则获取前一天的合约代码,如果是当天15点后晚盘,则获取今天的的合约代码\n", " now = datetime.now()\n", " if now.hour < 15:\n", " data_str = (now - timedelta(days=1)).date().strftime('%Y%m%d')\n", " else:\n", " data_str = now.date().strftime('%Y%m%d')\n", "\n", " # 拆分主连合约代码为交易标识和交易所代码(交易市场)\n", " main_symbol = pro.fut_mapping(ts_code=main_symbol_code, trade_date = data_str).loc[0,'mapping_ts_code'].split('.')[0]\n", " exchange_id = pro.fut_mapping(ts_code=main_symbol_code, trade_date = data_str).loc[0,'mapping_ts_code'].split('.')[1]\n", "\n", " # 拆分交易标识中的合约产品代码和交割月份\n", " for char in main_symbol:\n", " if char.isalpha():\n", " alpha_chars += char\n", " elif char.isdigit():\n", " numeric_chars += char\n", " \n", " # 监理交易所映射\n", " exchange = {'CFX': 'CFFEX', 'SHF':'SHFE', 'DCE':'DCE', 'GFE':'GFEX', 'INE':'INE', 'ZCE':'CZCE'}\n", "\n", " # 计算per_unit:交易单位(每手)和转换后交易所识别的main_code:主连代码\n", " if exchange_id == 'CFX' or exchange_id == 'SHF' or exchange_id == 'DCE' or exchange_id == 'GFE' or exchange_id == 'INE':\n", " df = pro.fut_basic(exchange = exchange[exchange_id], fut_type='1', fut_code = alpha_chars, fields='ts_code,symbol,exchange,name,per_unit')\n", " # ts_code = df[df['symbol'] == main_symbol]['ts_code'].iloc[0]\n", " per_unit = df[df['symbol'] == main_symbol]['per_unit'].iloc[0]\n", "\n", " # ds = pro.fut_settle(trade_date = data_str, ts_code =ts_code)\n", " # ds['margin_rate'] = (ds['long_margin_rate'] + ds['short_margin_rate'])/2\n", " # margin_rate = ds['margin_rate'].iloc[0]\n", " \n", " \n", " if exchange_id == 'CFX':\n", " main_code = main_symbol\n", " elif exchange_id == 'SHF' or exchange_id == 'DCE' or exchange_id == 'GFE' or exchange_id == 'INE':\n", " lower_alpha_chars = str.lower(alpha_chars) \n", " main_code = lower_alpha_chars + numeric_chars\n", " elif exchange_id == 'ZCE':\n", " true_numeric_chars = numeric_chars[1:]\n", " main_code = alpha_chars + true_numeric_chars \n", " df = pro.fut_basic(exchange = exchange[exchange_id], fut_type='1', fut_code = alpha_chars, fields='ts_code,symbol,exchange,name,per_unit')\n", " per_unit = df[df['symbol'] == main_code]['per_unit'].iloc[0]\n", " main_code = alpha_chars + true_numeric_chars\n", "\n", " print(\"最终使用的主连代码:\",main_code) \n", " print(\"%s的交易单位(每手):%s\"%(main_symbol, per_unit))\n", " return main_code\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sb_1 = get_main_contact_on_time('IH.CFX')\n", "sb_2 = get_main_contact_on_time('cu.SHF')\n", "sb_3 = get_main_contact_on_time('eb.DCE')\n", "sb_4 = get_main_contact_on_time('si.GFE')\n", "sb_5 = get_main_contact_on_time('sc.INE') \n", "sb_6 = get_main_contact_on_time('SA.ZCE')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# df = pro.fut_basic(exchange='DCE', fut_type='1',fut_code = 'j' , fields='ts_code,symbol,exchange,name,fut_code,multiplier,trade_unit,per_unit,quote_unit,quote_unit_desc,d_mode_desc,list_date,delist_date,d_month,last_ddate,trade_time_desc')\n", "# df = pro.fut_basic(exchange='SHFE', fut_type='1', fut_code = 'au', fields='ts_code,symbol,name,list_date,delist_date')\n", "df = pro.fut_basic(exchange='CZCE', fut_type='1', fut_code = 'SA', fields='ts_code,symbol,exchange,name,fut_code,per_unit')\n", "# index_of_value = df.index[df['symbol'] == 'AU2408']\n", "df.head()\n", "value = df[df['symbol'] == 'SA409']['per_unit'].iloc[0]\n", "print(value)\n", "# df.loc[index_of_value, 'per_unit'].value\n", "# df.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df = pro.fut_mapping(ts_code='SA.ZCE')\n", "print(df)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# ds = pro.fut_settle(trade_date = '20240625', ts_code ='SA2409.ZCE')\n", "# ds = pro.fut_settle(trade_date='20230625', exchange='ZCE')\n", "# ds = pro.fut_settle(ts_code='SA409.ZCE', exchange='CZCE')\n", "# pro.fut_settle(trade_date='20181114', exchange='CZCE')\n", "pro.fut_settle(ts_code='AP2510.ZCE', exchange='CZCE')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ds.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ds['margin_rate'] = round((ds['long_margin_rate'] + ds['short_margin_rate'])/2,2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ds['margin_rate'].iloc[0]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "value = df.loc[index_of_value, 'per_unit'].iloc[0]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(value)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_IH = pro.fut_mapping(ts_code='IH.CFX')\n", "print(df_IH)\n", "df_IH.to_csv(r\"E:\\data\\mapping_ts_code_IH.csv\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_IF = pro.fut_mapping(ts_code='IF.CFX')\n", "print(df_IF)\n", "df_IF.to_csv(r\"E:\\data\\mapping_ts_code_IF.csv\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_IC = pro.fut_mapping(ts_code='IC.CFX')\n", "print(df_IC)\n", "df_IC.to_csv(r\"E:\\data\\mapping_ts_code_IC.csv\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_IM = pro.fut_mapping(ts_code='IM.CFX')\n", "print(df_IM)\n", "df_IM.to_csv(r\"E:\\data\\mapping_ts_code_IM.csv\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_TF = pro.fut_mapping(ts_code='TF.CFX')\n", "print(df_TF)\n", "df_TF.to_csv(r\"E:\\data\\mapping_ts_code_TF.csv\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_T = pro.fut_mapping(ts_code='T.CFX')\n", "print(df_T)\n", "df_T.to_csv(r\"E:\\data\\mapping_ts_code_T.csv\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_TS = pro.fut_mapping(ts_code='TS.CFX')\n", "print(df_TS)\n", "df_TS.to_csv(r\"E:\\data\\mapping_ts_code_TS.csv\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_TL = pro.fut_mapping(TL_code='TL.CFX')\n", "print(df_TL)\n", "df_TL.to_csv(r\"E:\\data\\mapping_TL_code_TL.csv\")" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'pro' is not defined", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[1], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m df_TL \u001b[38;5;241m=\u001b[39m \u001b[43mpro\u001b[49m\u001b[38;5;241m.\u001b[39mfut_mapping(ts_code\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mTL.CFX\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(df_TL)\n\u001b[0;32m 3\u001b[0m df_TL\u001b[38;5;241m.\u001b[39mto_csv(\u001b[38;5;124mr\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mD:\u001b[39m\u001b[38;5;124m\\\u001b[39m\u001b[38;5;124mdata\u001b[39m\u001b[38;5;124m\\\u001b[39m\u001b[38;5;124mmapping_TL_code_TL.csv\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", "\u001b[1;31mNameError\u001b[0m: name 'pro' is not defined" ] } ], "source": [ "df_TL = pro.fut_mapping(ts_code='TL.CFX')\n", "print(df_TL)\n", "df_TL.to_csv(r\"D:\\data\\mapping_TL_code_TL.csv\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import akshare as ak\n", "\n", "futures_comm_info_df = ak.futures_comm_info(symbol=\"上海国际能源交易中心\")\n", "print(futures_comm_info_df[\"保证金-买开\"])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "futures_fees_info_df = ak.futures_fees_info()\n", "print(futures_fees_info_df)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "futures_fees_info_df.to_csv(r'./futures_fees_info.csv', index=False)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "futures_display_main_sina_df = ak.futures_display_main_sina()\n", "print(futures_display_main_sina_df)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "url = 'https://www.9qihuo.com/hangqing' #上期所铜结算参数地址https://www.9qihuo.com/hangqing\n", "data =pd.read_html(url) #读取网页上的表格\n", "dt=data[4].drop([0],axis=0).append(data[5],ignore_index=True) #提取结算参数到DataFrame格式\n", "#调整格式\n", "dt.columns=dt.iloc[0]\n", "dt.drop([0],axis=0,inplace=True) \n", "dt.set_index('合约代码',inplace=True)\n", "print(dt) #输出铜的结算参数" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import requests\n", "from bs4 import BeautifulSoup\n", "import csv\n", "\n", "# 目标网址\n", "url = \"https://www.9qihuo.com/hangqing\"\n", "\n", "# 发送GET请求,禁用SSL验证\n", "response = requests.get(url, verify=False)\n", "response.encoding = 'utf-8' # 确保编码正确\n", "\n", "# 解析网页内容\n", "soup = BeautifulSoup(response.text, 'lxml')\n", "\n", "# 找到目标表格\n", "table = soup.find('table', {'id': 'tblhangqinglist'})\n", "\n", "# 初始化CSV文件\n", "with open('main_contacts.csv', mode='w', newline='', encoding='utf-8') as file:\n", " writer = csv.writer(file)\n", " \n", " # 遍历表格的所有行\n", " for row in table.find_all('tr'):\n", " # 获取每一行的所有单元格\n", " cols = row.find_all(['th', 'td'])\n", " # 提取文本内容并写入CSV文件\n", " writer.writerow([col.text.strip() for col in cols])\n", "\n", "print(\"表格已成功保存为main_contacts.csv\")\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "df = pd.read_csv('./main_contacts.csv')\n", "df.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df['交易品种'] = df['合约'].str.split(r'[()]', n=1, expand=True)[0]\n", "df['主连代码'] = df['合约'].str.split(r'[()]', n=2, expand=True)[1]\n", "\n", "# df['品种代码'] = df['主连代码'].str.split(str.isalpha(df['主连代码']), n=1, expand=True)[0]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import re\n", "\n", "# 创建示例DataFrame\n", "\n", "# 定义拆分字母和数字的函数\n", "def split_alpha_numeric(s):\n", " match = re.match(r\"([a-zA-Z]+)([0-9]+)\", s)\n", " if match:\n", " return match.groups()\n", " else:\n", " return (s, None) # 如果没有匹配,返回原始字符串和None\n", "\n", "# 应用函数并创建新列\n", "df[['品种代码', '交割月份']] = df['主连代码'].apply(lambda x: pd.Series(split_alpha_numeric(x)))\n", "\n", "print(df)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df.to_csv('./main_contacts_all.csv')" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "import subprocess\n", "import schedule\n", "import time\n", "from datetime import datetime\n", "\n", "# jerome:增加akshare库\n", "import akshare as ak\n", "\n", "# jerome:增加下列库用于爬虫获取主力连续代码\n", "import pandas as pd\n", "import requests\n", "from bs4 import BeautifulSoup\n", "import csv\n", "import re\n", "import os" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [], "source": [ "def get_futures_fees_info():\n", " futures_fees_info_df = ak.futures_fees_info()\n", " futures_fees_info_df.to_csv(r'./futures_fees_info.csv', index=False)\n", "\n", "def get_main_contacts():\n", " url = \"https://www.9qihuo.com/hangqing\"\n", "\n", " # 发送GET请求,禁用SSL验证\n", " response = requests.get(url, verify=False)\n", " response.encoding = 'utf-8' # 确保编码正确\n", "\n", " # 解析网页内容\n", " soup = BeautifulSoup(response.text, 'lxml')\n", "\n", " # 找到目标表格\n", " table = soup.find('table', {'id': 'tblhangqinglist'})\n", "\n", " # 初始化CSV文件\n", " with open('tmp_main_contacts.csv', mode='w', newline='', encoding='utf-8') as file:\n", " writer = csv.writer(file)\n", " \n", " # 遍历表格的所有行\n", " for row in table.find_all('tr'):\n", " # 获取每一行的所有单元格\n", " cols = row.find_all(['th', 'td'])\n", " # 提取文本内容并写入CSV文件\n", " writer.writerow([col.text.strip() for col in cols])\n", "\n", " df = pd.read_csv('./tmp_main_contacts.csv',encoding='utf-8')\n", " df['交易品种'] = df['合约'].str.split(r'[()]', n=1, expand=True)[0]\n", " df['主连代码'] = df['合约'].str.split(r'[()]', n=2, expand=True)[1]\n", "\n", " df[['品种代码', '交割月份']] = df['主连代码'].apply(lambda x: pd.Series(split_alpha_numeric(x)))\n", " df.to_csv('./main_contacts.csv')\n", "\n", " print(\"期货主力品种表已经保存为main_contacts.csv\")\n", " os.remove(\"./tmp_main_contacts.csv\")\n", "\n", "# 拆分字母和数字的函数\n", "def split_alpha_numeric(s):\n", " match = re.match(r\"([a-zA-Z]+)([0-9]+)\", s)\n", " if match:\n", " return match.groups()\n", " else:\n", " return (s, None) # 如果没有匹配,返回原始字符串和None" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [], "source": [ "get_futures_fees_info()" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "期货主力品种表已经保存为main_contacts.csv\n" ] } ], "source": [ "get_main_contacts()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.9" } }, "nbformat": 4, "nbformat_minor": 2 }