This commit is contained in:
louiscklaw
2025-01-31 19:28:53 +08:00
parent 72bacdd6b5
commit 843c590c8b
19 changed files with 1522 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
[InternetShortcut]
URL=https://www.cirium.com/thoughtcloud/most-on-time-airlines-airports-of-2023-unveiled-by-cirium/

BIN
bennchung1983/POWERPNT_dyXbeJCnDr.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@@ -0,0 +1,7 @@
git status .
@pause
git add .
git commit -m"update bennchung1983,"
start git push

BIN
bennchung1983/slide.pptx Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,497 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "d7e90f45",
"metadata": {},
"outputs": [],
"source": [
"#### Pandas is for using data structures\n",
"import pandas as pd\n",
"# statsmodels contain modules for regression and time series analysis\n",
"import statsmodels.api as sm\n",
"# numpy is for numerical computing of array and mayatrix\n",
"import numpy as np\n",
"# Matplotlib, Seaborn: plotting package\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns \n",
"# matplotlib Showing the plot right after the current code \n",
"%matplotlib inline\n",
"import warnings\n",
"warnings.filterwarnings('ignore')\n",
"# basic statistics package\n",
"import scipy.stats as stats\n",
"from statsmodels.stats.outliers_influence import variance_inflation_factor\n",
"import datetime"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "5159ee37",
"metadata": {},
"outputs": [],
"source": [
"# functions from last lab\n",
"def four_in_one(dataframe,model):\n",
" fitted_y = model.fittedvalues\n",
" studentized_residuals = model.get_influence().resid_studentized_internal\n",
" plt.figure(figsize=(10,10))\n",
" ax1 = plt.subplot(221)\n",
" stats.probplot(studentized_residuals, dist=\"norm\", plot=plt)\n",
" ax1.set_title('Normal Q-Q')\n",
" ax1.set_xlabel('Normal Quantiles')\n",
" ax1.set_ylabel('Studentized Residuals');\n",
"\n",
" ax2 = plt.subplot(222)\n",
" ax2.hist(studentized_residuals)\n",
" ax2.set_xlabel('Studentized Residuals')\n",
" ax2.set_ylabel('Count')\n",
" ax2.set_title('Histogram')\n",
"\n",
" ax3 = plt.subplot(223)\n",
" t = range(dataframe.shape[0])\n",
" ax3.scatter(t, studentized_residuals)\n",
" ax3.set_xlabel('Observation order')\n",
" ax3.set_ylabel('Residuals')\n",
" ax3.set_title('Time series plot of studentized residuals')\n",
"\n",
" ax4 = plt.subplot(224)\n",
" temp = pd.DataFrame({'fitted_y':fitted_y,'studentized_residuals':studentized_residuals})\n",
" ax4 = sns.residplot(data=temp,x=fitted_y, y=studentized_residuals,\n",
" lowess=True,\n",
" scatter_kws={'alpha': 0.5},\n",
" line_kws={'color': 'red', 'lw': 1, 'alpha': 0.8})\n",
" ax4.set_title('Internally Studentized Residuals vs Fitted values')\n",
" ax4.set_xlabel('Fitted values')\n",
" ax4.set_ylabel('Studentized Residuals');\n",
" \n",
"def getvif(X):\n",
" X = sm.add_constant(X)\n",
" vif = pd.DataFrame()\n",
" vif[\"VIF\"] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]\n",
" vif[\"Predictors\"] = X.columns\n",
" return(vif.drop(index = 0).round(2)) "
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "16326102",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>rBH</th>\n",
" <th>rSP</th>\n",
" <th>SmB</th>\n",
" <th>HmL</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Date</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1/2/2009</th>\n",
" <td>-0.121807</td>\n",
" <td>-0.109931</td>\n",
" <td>0.0005</td>\n",
" <td>-0.0695</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1/3/2009</th>\n",
" <td>0.103053</td>\n",
" <td>0.085404</td>\n",
" <td>0.0004</td>\n",
" <td>0.0348</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1/4/2009</th>\n",
" <td>0.084198</td>\n",
" <td>0.093925</td>\n",
" <td>0.0539</td>\n",
" <td>0.0536</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1/5/2009</th>\n",
" <td>-0.025532</td>\n",
" <td>0.053081</td>\n",
" <td>-0.0252</td>\n",
" <td>0.0027</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1/6/2009</th>\n",
" <td>-0.017467</td>\n",
" <td>0.000196</td>\n",
" <td>0.0263</td>\n",
" <td>-0.0273</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" rBH rSP SmB HmL\n",
"Date \n",
"1/2/2009 -0.121807 -0.109931 0.0005 -0.0695\n",
"1/3/2009 0.103053 0.085404 0.0004 0.0348\n",
"1/4/2009 0.084198 0.093925 0.0539 0.0536\n",
"1/5/2009 -0.025532 0.053081 -0.0252 0.0027\n",
"1/6/2009 -0.017467 0.000196 0.0263 -0.0273"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data = pd.read_csv(\"BH2009-2022.csv\",index_col=0)\n",
"data.head()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "7fd1d118",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(167, 4)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data.shape"
]
},
{
"cell_type": "markdown",
"id": "09cc26c8",
"metadata": {},
"source": [
"# Part I: CAPM model"
]
},
{
"cell_type": "markdown",
"id": "ebaa4598-7164-4b6c-ac8d-7d674fa4ee4f",
"metadata": {},
"source": [
"### Task 1: Split the data into train (first 155 observations) and test (remaining 12 observations) set"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "095d1d13",
"metadata": {},
"outputs": [],
"source": [
"train = $$code here$$\n",
"test = $$code here$$"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c0a06748",
"metadata": {},
"outputs": [],
"source": [
"train.shape, test.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "abff4aee-07cb-4ddd-8cd2-7f909b217b41",
"metadata": {},
"outputs": [],
"source": [
"Y = train[\"rBH\"]\n",
"X = train[\"rSP\"]"
]
},
{
"cell_type": "markdown",
"id": "f84493d2-6484-4e62-a196-888c72c657f4",
"metadata": {},
"source": [
"### Task 2: Using training set, fit a simple regression model(SLR). Report the adjusted R-square of the model."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "76e5007b-ec3f-4271-9c25-afd7cb2bd028",
"metadata": {},
"outputs": [],
"source": [
"SLR = $$code here$$\n",
"print(SLR.summary())"
]
},
{
"cell_type": "markdown",
"id": "b9fd7ede-dabc-47d9-918f-021ee1fae9b4",
"metadata": {},
"source": [
"### Report the adjusted R-square of the model.\n",
" "
]
},
{
"cell_type": "markdown",
"id": "3af44ff8",
"metadata": {},
"source": [
"# Part II: Multiple Regression Model"
]
},
{
"cell_type": "markdown",
"id": "3f8158d8-1c42-4226-99c3-0d04a026df5b",
"metadata": {},
"source": [
"### Task 3: Using training set, fit a multiple regression model with SmB and HmL explanatory variables in addition to rSP (MLR). Report the adjusted R-square of the model."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1f2dfad6",
"metadata": {},
"outputs": [],
"source": [
"X = $$code here$$\n",
"MLR = $$code here$$\n",
"print(MLR.summary())"
]
},
{
"cell_type": "markdown",
"id": "18e59124-7f05-414a-9284-fde621aa94cc",
"metadata": {},
"source": [
"### Report the adjusted R-square of the model.\n",
" "
]
},
{
"cell_type": "markdown",
"id": "fcb66422-678b-4d10-9aea-e56ae1c0adfa",
"metadata": {},
"source": [
"### Task 4: Checking the multicollinearity problem among rSP, SmB and HmL by \n",
" i) Scatter plot matrix \n",
" ii) VIF. \n",
"#### Is the multicollinearity problem exist?"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "284873a2",
"metadata": {},
"outputs": [],
"source": [
"$$code here$$ #<--code for scatter plot matrix"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cad9bd49-5030-4a95-a5b5-ae8677092fbe",
"metadata": {},
"outputs": [],
"source": [
"$$code here$$ #<--code for VIF"
]
},
{
"cell_type": "markdown",
"id": "aea04a9e",
"metadata": {},
"source": [
"### Is the multicollinearity problem exist?"
]
},
{
"cell_type": "markdown",
"id": "88eb43de",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"id": "ece7bda1-23e4-47e5-84ba-d0ab6eff9f06",
"metadata": {
"tags": []
},
"source": [
"### Task 5: From the fitted multiple regression model in Task 3\n",
" i) Is the model as a whole useful at 5% significant level? \n",
" ii) Which of them is not an useful explanatory variable at 5% significant level?"
]
},
{
"cell_type": "markdown",
"id": "413b5d9a-44c6-4f4e-91c4-3f82317b2b00",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"id": "fe0773af-c6ee-4dce-97c6-fe33af6310b8",
"metadata": {},
"source": [
"### Task 6: Execute model diagnostic on the model fitted from Task3 using the “four_in_one” function. Comment on the normality, constant variance assumption.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0b372cd7",
"metadata": {},
"outputs": [],
"source": [
"$$code here$$ #<--code for “four_in_one” function"
]
},
{
"cell_type": "markdown",
"id": "919fcacf",
"metadata": {},
"source": [
"### Comment on the normality, constant variance assumption."
]
},
{
"cell_type": "markdown",
"id": "52ff227e",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"id": "5b40b212",
"metadata": {},
"source": [
"# Part IV: Model Performance"
]
},
{
"cell_type": "markdown",
"id": "8cc559dd-6a77-4289-a451-ede8d00bbf90",
"metadata": {},
"source": [
"### Task 7: Compare the predictive power between SLR and MLR using the test set. Which one perform better in prediction?"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6e74fa4c",
"metadata": {},
"outputs": [],
"source": [
"Test_X_SLR = test['rSP']\n",
"Test_X_MLR = $$code here$$\n",
"\n",
"Test_Y_SLR = SLR.predict(sm.add_constant(Test_X_SLR))\n",
"Test_Y_MLR = $$code here$$"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d5af214f",
"metadata": {},
"outputs": [],
"source": [
"Test_Y = test[\"rBH\"]\n",
"\n",
"from sklearn.metrics import mean_squared_error\n",
"rmse_SLR = np.sqrt(mean_squared_error(Test_Y, Test_Y_SLR))\n",
"rmse_MLR = $$code here$$\n",
"print(\"RMSE for test set (SLR): \", rmse_SLR)\n",
"print(\"RMSE for test set (MLR): \", rmse_MLR)"
]
},
{
"cell_type": "markdown",
"id": "bd0c8483",
"metadata": {},
"source": [
"### Which one perform better in prediction?"
]
},
{
"cell_type": "markdown",
"id": "36d05636",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "f203f98c-2e57-4262-8fd8-5209825817af",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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": 5
}

View File

@@ -0,0 +1,168 @@
Date,rBH,rSP,SmB,HmL
1/2/2009,-0.121807334,-0.109931198,0.0005,-0.0695
1/3/2009,0.103053435,0.085404462,0.0004,0.0348
1/4/2009,0.084198385,0.093925079,0.0539,0.0536
1/5/2009,-0.025531915,0.053081446,-0.0252,0.0027
1/6/2009,-0.017467249,0.000195827,0.0263,-0.0273
1/7/2009,0.077777778,0.074141727,0.0187,0.0484
1/8/2009,0.039690722,0.033560189,-0.0108,0.0763
1/9/2009,0.001487357,0.035723346,0.0243,0.0104
1/10/2009,-0.01980198,-0.019762001,-0.0434,-0.042
1/11/2009,0.016161616,0.057364062,-0.0239,-0.0034
1/12/2009,-0.013916501,0.017770571,0.0604,-0.0017
1/1/2010,0.155241935,-0.036974246,0.004,0.0043
1/2/2010,0.045375218,0.028513689,0.0119,0.0323
1/3/2010,0.016694491,0.058796426,0.0148,0.0221
1/4/2010,-0.05316092,0.01475923,0.0487,0.0289
1/5/2010,-0.081638847,-0.081975842,0.0009,-0.0244
1/6/2010,0.133037485,-0.053882442,-0.0182,-0.047
1/7/2010,-0.025,0.06877785,0.0022,-0.0033
1/8/2010,0.014316239,-0.047449184,-0.0298,-0.0193
1/9/2010,0.049083632,0.087551103,0.0397,-0.0318
1/10/2010,-0.041767068,0.036855994,0.0119,-0.0251
1/11/2010,0.007544007,-0.00229025,0.0374,-0.0092
1/12/2010,0.002079867,0.06530004,0.0069,0.0376
1/1/2011,0.016396845,0.022645574,-0.0245,0.0075
1/2/2011,0.072493363,0.031956564,0.0153,0.0127
1/3/2011,-0.045696877,-0.001047313,0.0256,-0.0185
1/4/2011,-0.004389465,0.02849538,-0.0033,-0.0249
1/5/2011,-0.047895792,-0.013500953,-0.0067,-0.02
1/6/2011,-0.022479478,-0.018257461,-0.0015,-0.0039
1/7/2011,-0.039662375,-0.021474426,-0.0127,-0.009
1/8/2011,-0.015524664,-0.056791107,-0.0305,-0.0236
1/9/2011,-0.027047709,-0.071761988,-0.0331,-0.0172
1/10/2011,0.095037453,0.107723039,0.0328,0.001
1/11/2011,0.013253527,-0.005058715,-0.0016,-0.0045
1/12/2011,-0.031603376,0.008532764,-0.0059,0.0163
1/1/2012,0.027624069,0.043583062,0.0203,-0.0097
1/2/2012,7.63E-05,0.040589464,-0.0185,0.0043
1/3/2012,0.033628979,0.031332315,-0.0065,0.0114
1/4/2012,-0.00902379,-0.007497453,-0.0041,-0.0078
1/5/2012,-0.016142384,-0.062650726,0.0007,-0.0106
1/6/2012,0.05128313,0.039554982,0.0067,0.0062
1/7/2012,0.020008804,0.012597574,-0.0277,-0.0002
1/8/2012,-0.006944172,0.01976337,0.0048,0.013
1/9/2012,0.048514539,0.024236154,0.0051,0.016
1/10/2012,-0.024076865,-0.01978941,-0.0116,0.0359
1/11/2012,0.018617042,0.002846717,0.0064,-0.0084
1/12/2012,0.016252767,0.00706823,0.015,0.0351
1/1/2013,0.08813218,0.050428097,0.0033,0.0096
1/2/2013,0.046101114,0.011060649,-0.0028,0.0011
1/3/2013,0.024115334,0.035987724,0.0081,-0.0019
1/4/2013,0.017404658,0.018085768,-0.0236,0.0045
1/5/2013,0.077358491,0.020762812,0.0173,0.0263
1/6/2013,-0.015761821,-0.014999302,0.0133,0.0003
1/7/2013,0.03143535,0.04946208,0.0186,0.0057
1/8/2013,-0.039390454,-0.031298019,0.0028,-0.0269
1/9/2013,0.020113738,0.029749523,0.0291,-0.0122
1/10/2013,0.015163429,0.044595753,-0.0156,0.0125
1/11/2013,0.010150641,0.028049472,0.0129,0.0032
1/12/2013,0.018025751,0.023562792,-0.0045,-0.0002
1/1/2014,-0.047155705,-0.035582906,0.009,-0.0207
1/2/2014,0.024759455,0.04311703,0.0037,-0.0031
1/3/2014,0.078534092,0.006932166,-0.0185,0.0493
1/4/2014,0.0316253,0.006200789,-0.042,0.0117
1/5/2014,-0.006596818,0.02103028,-0.0188,-0.0013
1/6/2014,-0.0109375,0.019058332,0.0308,-0.007
1/7/2014,-0.009352291,-0.015079831,-0.0429,0.0003
1/8/2014,0.094384555,0.037655295,0.004,-0.0045
1/9/2014,0.004954342,-0.015513837,-0.0372,-0.0134
1/10/2014,0.014983084,0.023201461,0.042,-0.0181
1/11/2014,0.062214286,0.024533589,-0.0206,-0.0309
1/12/2014,0.0131576,-0.004188588,0.0249,0.0227
1/1/2015,-0.044845133,-0.031040806,-0.0055,-0.0358
1/2/2015,0.02462187,0.054892511,0.0061,-0.0186
1/3/2015,-0.016638032,-0.017396107,0.0304,-0.0037
1/4/2015,-0.018850575,0.00852082,-0.0303,0.0182
1/5/2015,0.00656045,0.010491382,0.0092,-0.0114
1/6/2015,-0.04632216,-0.021011672,0.029,-0.0079
1/7/2015,0.044666829,0.01974203,-0.0419,-0.0413
1/8/2015,-0.053593458,-0.062580818,0.0033,0.0277
1/9/2015,-0.035999427,-0.026442832,-0.0263,0.0056
1/10/2015,0.047920508,0.082983118,-0.0187,-0.0046
1/11/2015,-0.015816536,0.000504869,0.0359,-0.0042
1/12/2015,-0.017679778,-0.017530185,-0.0282,-0.0261
1/1/2016,-0.017391304,-0.050735322,-0.0343,0.0209
1/2/2016,0.042164026,-0.00412836,0.0071,-0.0057
1/3/2016,0.05378786,0.065991115,0.0082,0.0119
1/4/2016,0.026001405,0.002699398,0.0074,0.0328
1/5/2016,-0.033356164,0.015324602,-0.0018,-0.0166
1/6/2016,0.024941543,0.000910921,0.006,-0.0148
1/7/2016,-0.004493605,0.035609801,0.0251,-0.0127
1/8/2016,0.045185185,-0.001219243,0.0118,0.0313
1/9/2016,-0.042257264,-0.001234451,0.0213,-0.0123
1/10/2016,-0.002404958,-0.019425679,-0.0442,0.0412
1/11/2016,0.098748261,0.034174522,0.0567,0.0819
1/12/2016,0.030046414,0.018200762,0.0008,0.0356
1/1/2017,0.007615076,0.017884358,-0.0114,-0.0276
1/2/2017,0.045206927,0.03719816,-0.0202,-0.0168
1/3/2017,-0.028199144,-0.000389197,0.0114,-0.0332
1/4/2017,-0.008284971,0.009091209,0.0072,-0.021
1/5/2017,0.002663653,0.011576251,-0.0252,-0.0378
1/6/2017,0.025197231,0.004813775,0.0223,0.0148
1/7/2017,0.031747154,0.019348826,-0.0146,-0.0024
1/8/2017,0.032969793,0.000546433,-0.0167,-0.0209
1/9/2017,0.012120096,0.019302979,0.0446,0.0312
1/10/2017,0.020856082,0.022188135,-0.0193,0.0021
1/11/2017,0.039326844,0.028082628,-0.0058,-0.0008
1/12/2017,0.020926244,0.00983163,-0.0132,0.0005
1/1/2018,0.086609543,0.056178704,-0.0315,-0.0133
1/2/2018,-0.040587553,-0.038947372,0.0023,-0.0107
1/3/2018,-0.035938759,-0.026884499,0.0405,-0.0023
1/4/2018,-0.028251421,0.002718775,0.0114,0.0054
1/5/2018,-0.011869947,0.021608342,0.0526,-0.0318
1/6/2018,-0.017966574,0.004842436,0.0115,-0.0233
1/7/2018,0.069174585,0.036021556,-0.0222,0.0047
1/8/2018,0.047255845,0.030263211,0.0112,-0.0399
1/9/2018,0.013299557,0.004294287,-0.0228,-0.0169
1/10/2018,-0.038421875,-0.069403356,-0.0477,0.0344
1/11/2018,0.059456297,0.017859357,-0.0068,0.0027
1/12/2018,-0.061349693,-0.091776895,-0.0238,-0.0186
1/1/2019,0.017973856,0.078684402,0.029,-0.0045
1/2/2019,-0.029855538,0.029728889,0.0205,-0.0268
1/3/2019,-0.003259431,0.017924256,-0.0303,-0.041
1/4/2019,0.079229122,0.039313498,-0.0174,0.0214
1/5/2019,-0.086194168,-0.065777731,-0.0131,-0.0234
1/6/2019,0.071669023,0.068930164,0.0028,-0.0072
1/7/2019,-0.03041935,0.013128152,-0.0193,0.0047
1/8/2019,-0.018103711,-0.018091627,-0.0236,-0.0476
1/9/2019,0.028883654,0.017181178,-0.0097,0.0674
1/10/2019,0.022791118,0.020431771,0.0029,-0.0192
1/11/2019,0.036232634,0.034047037,0.0078,-0.0201
1/12/2019,0.027519327,0.028589819,0.0073,0.0176
1/1/2020,-0.010583351,-0.001628093,-0.031,-0.0622
1/2/2020,-0.080060477,-0.084110484,0.0107,-0.0379
1/3/2020,-0.120014494,-0.125119282,-0.0488,-0.1397
1/4/2020,0.035661765,0.126844038,0.0249,-0.0123
1/5/2020,-0.01086262,0.04528182,0.0248,-0.0489
1/6/2020,-0.040697674,0.018388396,0.027,-0.0217
1/7/2020,0.098507295,0.055101321,-0.0232,-0.0138
1/8/2020,0.115549789,0.070064667,-0.0022,-0.0295
1/9/2020,-0.023076688,-0.03922797,0.0004,-0.0268
1/10/2020,-0.054690454,-0.027665786,0.0436,0.0421
1/11/2020,0.136158678,0.107545635,0.0582,0.0214
1/12/2020,0.012007984,0.037121459,0.0489,-0.0151
1/1/2021,-0.010680965,-0.011136661,0.0734,0.0296
1/2/2021,0.059517582,0.026091451,0.0206,0.0718
1/3/2021,0.057935158,0.042438633,-0.0237,0.074
1/4/2021,0.069478509,0.052425321,-0.0319,-0.0094
1/5/2021,0.056969697,0.005486489,-0.0025,0.0708
1/6/2021,-0.039905963,0.02221401,0.017,-0.0782
1/7/2021,0.000714284,0.022748055,-0.0399,-0.0176
1/8/2021,0.02625925,0.028990416,-0.0043,-0.0016
1/9/2021,-0.043082112,-0.047569169,0.0072,0.0508
1/10/2021,0.052319151,0.069143836,-0.0235,-0.0048
1/11/2021,-0.037019926,-0.008333706,-0.0132,-0.0044
1/12/2021,0.081045683,0.043612914,-0.0166,0.0328
1/1/2022,0.042477511,-0.052585165,-0.0594,0.1275
1/2/2022,0.013622673,-0.031360492,0.0223,0.0304
1/3/2022,0.110700224,0.035773288,-0.016,-0.018
1/4/2022,-0.084286689,-0.087956712,-0.0141,0.0619
1/5/2022,-0.021245406,5.31776E-05,-0.0185,0.0841
1/6/2022,-0.137327286,-0.08392,0.0209,-0.0597
1/7/2022,0.104536007,0.091116392,0.0281,-0.041
1/8/2022,-0.067283595,-0.042440128,0.0139,0.0031
1/9/2022,-0.03521889,-0.093395672,-0.0082,0.0003
1/10/2022,0.094914754,0.079863414,0.001,0.0805
1/11/2022,0.079159645,0.053752893,-0.034,0.0139
1/12/2022,-0.024088032,-0.058971474,-0.0064,0.0136
1 Date rBH rSP SmB HmL
2 1/2/2009 -0.121807334 -0.109931198 0.0005 -0.0695
3 1/3/2009 0.103053435 0.085404462 0.0004 0.0348
4 1/4/2009 0.084198385 0.093925079 0.0539 0.0536
5 1/5/2009 -0.025531915 0.053081446 -0.0252 0.0027
6 1/6/2009 -0.017467249 0.000195827 0.0263 -0.0273
7 1/7/2009 0.077777778 0.074141727 0.0187 0.0484
8 1/8/2009 0.039690722 0.033560189 -0.0108 0.0763
9 1/9/2009 0.001487357 0.035723346 0.0243 0.0104
10 1/10/2009 -0.01980198 -0.019762001 -0.0434 -0.042
11 1/11/2009 0.016161616 0.057364062 -0.0239 -0.0034
12 1/12/2009 -0.013916501 0.017770571 0.0604 -0.0017
13 1/1/2010 0.155241935 -0.036974246 0.004 0.0043
14 1/2/2010 0.045375218 0.028513689 0.0119 0.0323
15 1/3/2010 0.016694491 0.058796426 0.0148 0.0221
16 1/4/2010 -0.05316092 0.01475923 0.0487 0.0289
17 1/5/2010 -0.081638847 -0.081975842 0.0009 -0.0244
18 1/6/2010 0.133037485 -0.053882442 -0.0182 -0.047
19 1/7/2010 -0.025 0.06877785 0.0022 -0.0033
20 1/8/2010 0.014316239 -0.047449184 -0.0298 -0.0193
21 1/9/2010 0.049083632 0.087551103 0.0397 -0.0318
22 1/10/2010 -0.041767068 0.036855994 0.0119 -0.0251
23 1/11/2010 0.007544007 -0.00229025 0.0374 -0.0092
24 1/12/2010 0.002079867 0.06530004 0.0069 0.0376
25 1/1/2011 0.016396845 0.022645574 -0.0245 0.0075
26 1/2/2011 0.072493363 0.031956564 0.0153 0.0127
27 1/3/2011 -0.045696877 -0.001047313 0.0256 -0.0185
28 1/4/2011 -0.004389465 0.02849538 -0.0033 -0.0249
29 1/5/2011 -0.047895792 -0.013500953 -0.0067 -0.02
30 1/6/2011 -0.022479478 -0.018257461 -0.0015 -0.0039
31 1/7/2011 -0.039662375 -0.021474426 -0.0127 -0.009
32 1/8/2011 -0.015524664 -0.056791107 -0.0305 -0.0236
33 1/9/2011 -0.027047709 -0.071761988 -0.0331 -0.0172
34 1/10/2011 0.095037453 0.107723039 0.0328 0.001
35 1/11/2011 0.013253527 -0.005058715 -0.0016 -0.0045
36 1/12/2011 -0.031603376 0.008532764 -0.0059 0.0163
37 1/1/2012 0.027624069 0.043583062 0.0203 -0.0097
38 1/2/2012 7.63E-05 0.040589464 -0.0185 0.0043
39 1/3/2012 0.033628979 0.031332315 -0.0065 0.0114
40 1/4/2012 -0.00902379 -0.007497453 -0.0041 -0.0078
41 1/5/2012 -0.016142384 -0.062650726 0.0007 -0.0106
42 1/6/2012 0.05128313 0.039554982 0.0067 0.0062
43 1/7/2012 0.020008804 0.012597574 -0.0277 -0.0002
44 1/8/2012 -0.006944172 0.01976337 0.0048 0.013
45 1/9/2012 0.048514539 0.024236154 0.0051 0.016
46 1/10/2012 -0.024076865 -0.01978941 -0.0116 0.0359
47 1/11/2012 0.018617042 0.002846717 0.0064 -0.0084
48 1/12/2012 0.016252767 0.00706823 0.015 0.0351
49 1/1/2013 0.08813218 0.050428097 0.0033 0.0096
50 1/2/2013 0.046101114 0.011060649 -0.0028 0.0011
51 1/3/2013 0.024115334 0.035987724 0.0081 -0.0019
52 1/4/2013 0.017404658 0.018085768 -0.0236 0.0045
53 1/5/2013 0.077358491 0.020762812 0.0173 0.0263
54 1/6/2013 -0.015761821 -0.014999302 0.0133 0.0003
55 1/7/2013 0.03143535 0.04946208 0.0186 0.0057
56 1/8/2013 -0.039390454 -0.031298019 0.0028 -0.0269
57 1/9/2013 0.020113738 0.029749523 0.0291 -0.0122
58 1/10/2013 0.015163429 0.044595753 -0.0156 0.0125
59 1/11/2013 0.010150641 0.028049472 0.0129 0.0032
60 1/12/2013 0.018025751 0.023562792 -0.0045 -0.0002
61 1/1/2014 -0.047155705 -0.035582906 0.009 -0.0207
62 1/2/2014 0.024759455 0.04311703 0.0037 -0.0031
63 1/3/2014 0.078534092 0.006932166 -0.0185 0.0493
64 1/4/2014 0.0316253 0.006200789 -0.042 0.0117
65 1/5/2014 -0.006596818 0.02103028 -0.0188 -0.0013
66 1/6/2014 -0.0109375 0.019058332 0.0308 -0.007
67 1/7/2014 -0.009352291 -0.015079831 -0.0429 0.0003
68 1/8/2014 0.094384555 0.037655295 0.004 -0.0045
69 1/9/2014 0.004954342 -0.015513837 -0.0372 -0.0134
70 1/10/2014 0.014983084 0.023201461 0.042 -0.0181
71 1/11/2014 0.062214286 0.024533589 -0.0206 -0.0309
72 1/12/2014 0.0131576 -0.004188588 0.0249 0.0227
73 1/1/2015 -0.044845133 -0.031040806 -0.0055 -0.0358
74 1/2/2015 0.02462187 0.054892511 0.0061 -0.0186
75 1/3/2015 -0.016638032 -0.017396107 0.0304 -0.0037
76 1/4/2015 -0.018850575 0.00852082 -0.0303 0.0182
77 1/5/2015 0.00656045 0.010491382 0.0092 -0.0114
78 1/6/2015 -0.04632216 -0.021011672 0.029 -0.0079
79 1/7/2015 0.044666829 0.01974203 -0.0419 -0.0413
80 1/8/2015 -0.053593458 -0.062580818 0.0033 0.0277
81 1/9/2015 -0.035999427 -0.026442832 -0.0263 0.0056
82 1/10/2015 0.047920508 0.082983118 -0.0187 -0.0046
83 1/11/2015 -0.015816536 0.000504869 0.0359 -0.0042
84 1/12/2015 -0.017679778 -0.017530185 -0.0282 -0.0261
85 1/1/2016 -0.017391304 -0.050735322 -0.0343 0.0209
86 1/2/2016 0.042164026 -0.00412836 0.0071 -0.0057
87 1/3/2016 0.05378786 0.065991115 0.0082 0.0119
88 1/4/2016 0.026001405 0.002699398 0.0074 0.0328
89 1/5/2016 -0.033356164 0.015324602 -0.0018 -0.0166
90 1/6/2016 0.024941543 0.000910921 0.006 -0.0148
91 1/7/2016 -0.004493605 0.035609801 0.0251 -0.0127
92 1/8/2016 0.045185185 -0.001219243 0.0118 0.0313
93 1/9/2016 -0.042257264 -0.001234451 0.0213 -0.0123
94 1/10/2016 -0.002404958 -0.019425679 -0.0442 0.0412
95 1/11/2016 0.098748261 0.034174522 0.0567 0.0819
96 1/12/2016 0.030046414 0.018200762 0.0008 0.0356
97 1/1/2017 0.007615076 0.017884358 -0.0114 -0.0276
98 1/2/2017 0.045206927 0.03719816 -0.0202 -0.0168
99 1/3/2017 -0.028199144 -0.000389197 0.0114 -0.0332
100 1/4/2017 -0.008284971 0.009091209 0.0072 -0.021
101 1/5/2017 0.002663653 0.011576251 -0.0252 -0.0378
102 1/6/2017 0.025197231 0.004813775 0.0223 0.0148
103 1/7/2017 0.031747154 0.019348826 -0.0146 -0.0024
104 1/8/2017 0.032969793 0.000546433 -0.0167 -0.0209
105 1/9/2017 0.012120096 0.019302979 0.0446 0.0312
106 1/10/2017 0.020856082 0.022188135 -0.0193 0.0021
107 1/11/2017 0.039326844 0.028082628 -0.0058 -0.0008
108 1/12/2017 0.020926244 0.00983163 -0.0132 0.0005
109 1/1/2018 0.086609543 0.056178704 -0.0315 -0.0133
110 1/2/2018 -0.040587553 -0.038947372 0.0023 -0.0107
111 1/3/2018 -0.035938759 -0.026884499 0.0405 -0.0023
112 1/4/2018 -0.028251421 0.002718775 0.0114 0.0054
113 1/5/2018 -0.011869947 0.021608342 0.0526 -0.0318
114 1/6/2018 -0.017966574 0.004842436 0.0115 -0.0233
115 1/7/2018 0.069174585 0.036021556 -0.0222 0.0047
116 1/8/2018 0.047255845 0.030263211 0.0112 -0.0399
117 1/9/2018 0.013299557 0.004294287 -0.0228 -0.0169
118 1/10/2018 -0.038421875 -0.069403356 -0.0477 0.0344
119 1/11/2018 0.059456297 0.017859357 -0.0068 0.0027
120 1/12/2018 -0.061349693 -0.091776895 -0.0238 -0.0186
121 1/1/2019 0.017973856 0.078684402 0.029 -0.0045
122 1/2/2019 -0.029855538 0.029728889 0.0205 -0.0268
123 1/3/2019 -0.003259431 0.017924256 -0.0303 -0.041
124 1/4/2019 0.079229122 0.039313498 -0.0174 0.0214
125 1/5/2019 -0.086194168 -0.065777731 -0.0131 -0.0234
126 1/6/2019 0.071669023 0.068930164 0.0028 -0.0072
127 1/7/2019 -0.03041935 0.013128152 -0.0193 0.0047
128 1/8/2019 -0.018103711 -0.018091627 -0.0236 -0.0476
129 1/9/2019 0.028883654 0.017181178 -0.0097 0.0674
130 1/10/2019 0.022791118 0.020431771 0.0029 -0.0192
131 1/11/2019 0.036232634 0.034047037 0.0078 -0.0201
132 1/12/2019 0.027519327 0.028589819 0.0073 0.0176
133 1/1/2020 -0.010583351 -0.001628093 -0.031 -0.0622
134 1/2/2020 -0.080060477 -0.084110484 0.0107 -0.0379
135 1/3/2020 -0.120014494 -0.125119282 -0.0488 -0.1397
136 1/4/2020 0.035661765 0.126844038 0.0249 -0.0123
137 1/5/2020 -0.01086262 0.04528182 0.0248 -0.0489
138 1/6/2020 -0.040697674 0.018388396 0.027 -0.0217
139 1/7/2020 0.098507295 0.055101321 -0.0232 -0.0138
140 1/8/2020 0.115549789 0.070064667 -0.0022 -0.0295
141 1/9/2020 -0.023076688 -0.03922797 0.0004 -0.0268
142 1/10/2020 -0.054690454 -0.027665786 0.0436 0.0421
143 1/11/2020 0.136158678 0.107545635 0.0582 0.0214
144 1/12/2020 0.012007984 0.037121459 0.0489 -0.0151
145 1/1/2021 -0.010680965 -0.011136661 0.0734 0.0296
146 1/2/2021 0.059517582 0.026091451 0.0206 0.0718
147 1/3/2021 0.057935158 0.042438633 -0.0237 0.074
148 1/4/2021 0.069478509 0.052425321 -0.0319 -0.0094
149 1/5/2021 0.056969697 0.005486489 -0.0025 0.0708
150 1/6/2021 -0.039905963 0.02221401 0.017 -0.0782
151 1/7/2021 0.000714284 0.022748055 -0.0399 -0.0176
152 1/8/2021 0.02625925 0.028990416 -0.0043 -0.0016
153 1/9/2021 -0.043082112 -0.047569169 0.0072 0.0508
154 1/10/2021 0.052319151 0.069143836 -0.0235 -0.0048
155 1/11/2021 -0.037019926 -0.008333706 -0.0132 -0.0044
156 1/12/2021 0.081045683 0.043612914 -0.0166 0.0328
157 1/1/2022 0.042477511 -0.052585165 -0.0594 0.1275
158 1/2/2022 0.013622673 -0.031360492 0.0223 0.0304
159 1/3/2022 0.110700224 0.035773288 -0.016 -0.018
160 1/4/2022 -0.084286689 -0.087956712 -0.0141 0.0619
161 1/5/2022 -0.021245406 5.31776E-05 -0.0185 0.0841
162 1/6/2022 -0.137327286 -0.08392 0.0209 -0.0597
163 1/7/2022 0.104536007 0.091116392 0.0281 -0.041
164 1/8/2022 -0.067283595 -0.042440128 0.0139 0.0031
165 1/9/2022 -0.03521889 -0.093395672 -0.0082 0.0003
166 1/10/2022 0.094914754 0.079863414 0.001 0.0805
167 1/11/2022 0.079159645 0.053752893 -0.034 0.0139
168 1/12/2022 -0.024088032 -0.058971474 -0.0064 0.0136

View File

@@ -0,0 +1,7 @@
git status .
@pause
git add .
git commit -m"update bettyphan789,"
start git push

23
bettyphan789/package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "bettyphan789",
"version": "1.0.0",
"description": "",
"main": "index.js",
"directories": {
"doc": "docs"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"gitUpdate": "git add . && git commit -m'update bettyphan789,'"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"bootstrap": "^5.2.3",
"react-bootstrap": "^2.6.0"
},
"devDependencies": {}
}

7
calvin312321/meta.md Normal file
View File

@@ -0,0 +1,7 @@
---
tags: [rude]
---
# calvin312321
02-jan-2025 rude, clever (not in a good way) and a lot of questions

View File

@@ -0,0 +1,160 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/

View File

@@ -0,0 +1,26 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="webhook_app"
type="PythonConfigurationType" factoryName="Python">
<module name="TWS-orders-placement-via-Tradinview-webhooks"/>
<option name="INTERPRETER_OPTIONS" value=""/>
<option name="PARENT_ENVS" value="true"/>
<envs>
<env name="PYTHONUNBUFFERED" value="1"/>
</envs>
<option name="SDK_HOME" value=""/>
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$"/>
<option name="IS_MODULE_SDK" value="true"/>
<option name="ADD_CONTENT_ROOTS" value="true"/>
<option name="ADD_SOURCE_ROOTS" value="true"/>
<EXTENSION ID="PythonCoverageRunConfigurationExtension"
runner="coverage.py"/>
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py"/>
<option name="PARAMETERS" value=""/>
<option name="SHOW_COMMAND_LINE" value="false"/>
<option name="EMULATE_TERMINAL" value="false"/>
<option name="MODULE_MODE" value="false"/>
<option name="REDIRECT_INPUT" value="false"/>
<option name="INPUT_FILE" value=""/>
<method v="2"/>
</configuration>
</component>

View File

@@ -0,0 +1,65 @@
## Placing orders to IB TWS via Tradingview alerts webhooks
Connect TradingView with Interactive Brokers to process automated signals
as entries and exits in an IB brokerage account.
#### Python version 3.10
### Configuring the alert Webhook and installing ngrock
You'll need to install `ngrock` (URL to the download
page- https://ngrok.com/download)
and at least Pro TradingView subscription for placing webhooks in alerts,
and redirect them to your localhost.
Please, do not forget to add Authtoken from ngrock
- https://dashboard.ngrok.com/get-started/your-authtoken
After that you'll be able to run ngrock server:
```shell
$ ngrok http 5000
```
Copy the URL from `Forwarding` line and paste it into the alert Webhook line.
Add `/webhook` to the following URL. <b>Note: that webhooks are now available from Premium plan on TradingView<b>
Then, add the message to the `Message` field in the Alert navigation and click
Save:
```json
{
"message": "YourMessage",
"symbol": "{{ticker}}",
"price": "{{close}}",
"timeframe": "{{interval}}"
}
```
---
### Requirements
To run the application, please do not forget to install the following
requirements. You can do it in your terminal via the following command:
```shell
$ pip3 install --requirement requirements.txt
```
---
### Run app
To run the app via terminal do not forget to change the directory
to `src`.
After that you can simply type this command in your terminal:
```shell
$ python3 app.py
# or
$ chmod +x app.py
$ ./app.py
```

View File

@@ -0,0 +1,5 @@
# Core
Flask==2.1.2
ib_insync==0.9.70
sanic==22.3.2
websockets==10.0

View File

@@ -0,0 +1,8 @@
"""
The flask application package.
"""
from flask import Flask
import src.app
app = Flask(__name__)

View File

@@ -0,0 +1,374 @@
#!/usr/bin/env python3
"""
Routes and views for the application.
"""
import os
import sys
import re
import asyncio
from ib_insync import IB, MarketOrder, ExecutionFilter
from sanic import Sanic, response
from sanic.exceptions import InvalidUsage
import logging
from contract import get_next_contract_month, contract_type_check
import time
# Create the Sanic app
app = Sanic("unique_app_name")
# Initialize the logger
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
# IB constants
TWS_HOST = "127.0.0.1"
TWS_LIVE_PORT = 7496
TWS_PAPER_PORT = 7497
IBG_HOST = "127.0.0.1"
IBG_LIVE_PORT = 4001
IBG_PAPER_PORT = 4002
# Configuration: Set to True for paper trading, False for live trading
USE_PAPER_TRADING = True
# Configuration: Set to True for IB Gateway, False for TWS
USE_IB_GATEWAY = True
# Determine the correct host and port based on the configuration
if USE_IB_GATEWAY:
HOST = IBG_HOST
PORT = IBG_PAPER_PORT if USE_PAPER_TRADING else IBG_LIVE_PORT
else:
HOST = TWS_HOST
PORT = TWS_PAPER_PORT if USE_PAPER_TRADING else TWS_LIVE_PORT
# Initialize the IB connection
app_ib = IB()
# Check every minute if we need to reconnect to IB
async def check_if_reconnect() -> None:
global app_ib
logger.info("Checking if we need to reconnect...")
# Reconnect if needed
if app_ib is None or not app_ib.isConnected():
try:
logger.info("Reconnecting...")
if app_ib is not None:
app_ib.disconnect()
await app_ib.connectAsync(HOST, PORT, clientId=0) # Using clientId=0 as Master Client
app_ib.errorEvent += check_on_ib_error
logger.info("Successfully reconnected to TWS")
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
file_name = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
logger.error(f"Exception: {exc_type}, File: {file_name}, Line: {exc_tb.tb_lineno}")
logger.warning(f"Make sure TWS or Gateway is open with the correct port: {str(e)}")
# Helper function to wait for the order to be filled
async def wait_for_order_fill(trade, timeout=60):
start_time = time.time()
while trade.orderStatus.status not in ('Filled', 'Cancelled'):
if time.time() - start_time > timeout:
raise TimeoutError("Order fill timeout")
await app_ib.sleep(1)
return trade.orderStatus.status
# Request account updates
def request_account_updates(subscribe=True, accountCode=""):
app_ib.reqAccountUpdates(subscribe, accountCode)
# Event handler for order status
def on_order_status(trade):
logger.info(f"Order Status: OrderId={trade.order.orderId}, Status={trade.orderStatus.status}, Filled={trade.orderStatus.filled}, Remaining={trade.orderStatus.remaining}, AvgFillPrice={trade.orderStatus.avgFillPrice}")
# Event handler for account updates
def on_account_update(account, key, value, currency):
logger.info(f"Account update: Account={account}, Key={key}, Value={value}, Currency={currency}")
# Event handler for portfolio updates
def on_portfolio_update(account, contract, position, marketPrice, marketValue, averageCost, unrealizedPNL, realizedPNL):
logger.info(f"Portfolio update: Account={account}, Contract={contract}, Position={position}, MarketPrice={marketPrice}, MarketValue={marketValue}, AverageCost={averageCost}, UnrealizedPNL={unrealizedPNL}, RealizedPNL={realizedPNL}")
# Event handler for open orders
def on_open_order(trade):
logger.info(f"Open order: OrderId={trade.order.orderId}, Contract={trade.contract}, Order={trade.order}, OrderState={trade.orderState}")
# Event handler for IB error
def check_on_ib_error(reqId, error_code, error_string, contract):
logger.error(f"Error code: {error_code}, Message: {error_string}")
# Set event handlers
def set_event_handlers():
app_ib.orderStatusEvent += on_order_status
app_ib.accountSummaryEvent += on_account_update
app_ib.updatePortfolioEvent += on_portfolio_update
app_ib.openOrderEvent += on_open_order
app_ib.errorEvent += check_on_ib_error
# Periodic update function
async def periodic_update():
while True:
request_account_updates()
await asyncio.sleep(60) # Update every 60 seconds
@app.route('/portfolio', methods=['GET'])
async def portfolio(request) -> response.HTTPResponse:
if request.method == 'GET':
try:
await check_if_reconnect()
positions = await app_ib.reqPositions() # Use reqPositions to get real-time positions
if not positions:
logger.error("No positions retrieved from IB TWS API.")
return response.json({"status": "error", "message": "Failed to retrieve positions from IB TWS API."}, status=400)
portfolio_data = []
for position in positions:
contract = position.contract
avg_price = position.avgCost
quantity = position.position
unrealized_pnl = position.unrealizedPNL
realized_pnl = position.realizedPNL
portfolio_data.append({
"Instrument": contract.symbol,
"Average Price": avg_price,
"Positions": quantity,
"Unrealized P&L": unrealized_pnl,
"Realized P&L": realized_pnl
})
return response.json(portfolio_data)
except Exception as e:
logger.error(f"Error retrieving portfolio: {e}")
return response.json({"status": "error", "message": "Failed to retrieve portfolio"}, status=500)
return response.json({"status": "error", "message": "Invalid request method"}, status=405)
@app.route('/webhook', methods=['POST'])
async def webhook(request) -> response.HTTPResponse:
if request.method == 'POST':
try:
# Check if we need to reconnect with IB
await check_if_reconnect()
# Log the raw request body for debugging
raw_body = request.body.decode('utf-8')
logger.info(f"Received raw body: {raw_body}")
# Extract the required fields using regular expressions
action_pattern = r"order (?P<action>\w+) (?P<contracts>\d+) @ [\d\.]+ filled on (?P<ticker>\w+)"
position_pattern = r"New strategy position is (?P<position_size>-?\d+)"
action_match = re.search(action_pattern, raw_body)
position_match = re.search(position_pattern, raw_body)
if not action_match or not position_match:
logger.error("Failed to parse webhook message.")
return response.json({"status": "error", "message": "Failed to parse webhook message."}, status=400)
action = action_match.group("action").upper()
contracts = int(action_match.group("contracts"))
ticker = action_match.group("ticker")
position_size = int(position_match.group("position_size"))
logger.info(f"Parsed values - Action: {action}, Contracts: {contracts}, Ticker: {ticker}, Position Size: {position_size}")
# Determine the IB ticker based on the TradingView ticker
ib_ticker = None
if ticker == "SPX":
ib_ticker = "MES"
elif ticker == "NDX":
ib_ticker = "MNQ"
elif ticker == "HSI":
ib_ticker = "MHI"
elif ticker == "TOPIX":
ib_ticker = "MNTPX"
else:
logger.error(f"Invalid ticker: {ticker}")
return response.json({"status": "error", "message": "Invalid ticker"}, status=400)
# Map TradingView actions to IB actions
if action not in ["BUY", "SELL"]:
logger.error(f"Invalid action: {action}")
return response.json({"status": "error", "message": "Invalid action"}, status=400)
# Get the current contract month
current_contract_month = get_next_contract_month(ib_ticker)
current_contract = contract_type_check(ib_ticker, contract_month=current_contract_month)
if not current_contract:
return response.json({"status": "error", "message": "Invalid contract"}, status=400)
# 1. Place Initial Order: Execute the webhook order with contract month as of today
initial_order = MarketOrder(action, contracts, account=app_ib.wrapper.accounts[0])
logger.info(f"Placing initial order: {action} {contracts} contracts of {ib_ticker}")
# Place the order
try:
trade = app_ib.placeOrder(current_contract, initial_order)
logger.info(f"Order placed: {trade}")
# Log order status after placing
await asyncio.sleep(2) # Wait for a moment to allow the order to process
logger.info(f"Order status after placing: {trade.orderStatus.status}")
# Check for errors in the IB API
if trade.orderStatus.status == 'PendingSubmit':
logger.error("Order stuck in PendingSubmit.")
return response.json({"status": "error", "message": "Order stuck in PendingSubmit."}, status=400)
# 2. Wait for the initial order to be filled or cancelled
order_status = await wait_for_order_fill(trade)
logger.info(f"Order status after waiting: {order_status}")
if order_status != 'Filled':
logger.error("Order was not filled.")
return response.json({"status": "error", "message": "Order was not filled."}, status=400)
# 3. Retrieve Execution Details: Retrieve execution details for the order
exec_filter = ExecutionFilter(clientId=0)
executions = await app_ib.reqExecutions(exec_filter)
for execution in executions:
if execution.orderId == trade.order.orderId:
logger.info(f"Execution details: {execution}")
# 4. Retrieve Latest Position Details: Retrieve the current positions from IB TWS API
positions = await app_ib.reqPositions() # Use reqPositions to get real-time positions
if not positions:
logger.error("No positions retrieved from IB TWS API.")
return response.json({"status": "error", "message": "Failed to retrieve positions from IB TWS API."}, status=400)
current_position = sum(pos.position for pos in positions if pos.contract.symbol == ib_ticker)
ticker_positions = {pos.contract.symbol: pos.position for pos in positions}
logger.info(f"Current Positions: {ticker_positions}")
return response.json({"status": "success", "message": "Order placed and position details retrieved."})
except Exception as e:
logger.error(f"Error processing webhook: {e}")
return response.json({"status": "error", "message": f"Failed to process webhook: {str(e)}"}, status=500)
except InvalidUsage as e:
logger.error(f"Invalid JSON received: {e}")
return response.json({"status": "error", "message": "Invalid JSON format"}, status=400)
except Exception as e:
logger.error(f"Error processing webhook: {e}")
return response.json({"status": "error", "message": f"Failed to process webhook: {str(e)}"}, status=500)
return response.json({"status": "error", "message": "Invalid request method"}, status=405)
@app.route('/adjust_positions', methods=['POST'])
async def adjust_positions(request) -> response.HTTPResponse:
if request.method == 'POST':
try:
# Check if we need to reconnect with IB
await check_if_reconnect()
# Log the raw request body for debugging
raw_body = request.body.decode('utf-8')
logger.info(f"Received raw body: {raw_body}")
# Extract the required fields using regular expressions
action_pattern = r"order (?P<action>\w+) (?P<contracts>\d+) @ [\d\.]+ filled on (?P<ticker>\w+)"
position_pattern = r"New strategy position is (?P<position_size>-?\d+)"
action_match = re.search(action_pattern, raw_body)
position_match = re.search(position_pattern, raw_body)
if not action_match or not position_match:
logger.error("Failed to parse webhook message.")
return response.json({"status": "error", "message": "Failed to parse webhook message."}, status=400)
action = action_match.group("action").upper()
contracts = int(action_match.group("contracts"))
ticker = action_match.group("ticker")
position_size = int(position_match.group("position_size"))
logger.info(f"Parsed values - Action: {action}, Contracts: {contracts}, Ticker: {ticker}, Position Size: {position_size}")
# Determine the IB ticker based on the TradingView ticker
ib_ticker = None
if ticker == "SPX":
ib_ticker = "MES"
elif ticker == "NDX":
ib_ticker = "MNQ"
elif ticker == "HSI":
ib_ticker = "MHI"
elif ticker == "TOPIX":
ib_ticker = "MNTPX"
else:
logger.error(f"Invalid ticker: {ticker}")
return response.json({"status": "error", "message": "Invalid ticker"}, status=400)
# Get the current contract month
current_contract_month = get_next_contract_month(ib_ticker)
correct_contract = contract_type_check(ib_ticker, contract_month=current_contract_month)
rollover_needed = get_next_contract_month(ib_ticker, check_rollover=True)
positions = await app_ib.reqPositions()
positions_in_correct_month = [pos for pos in positions if pos.contract.lastTradeDateOrContractMonth == current_contract_month]
positions_not_in_correct_month = [pos for pos in positions if pos.contract.lastTradeDateOrContractMonth != current_contract_month]
# Contract month rollover if needed
if positions_not_in_correct_month:
logger.info(f"Contract month rollover needed: Adjusting positions to the correct contract month {current_contract_month}")
for pos in positions_not_in_correct_month:
close_action = "SELL" if pos.position > 0 else "BUY"
close_order = MarketOrder(close_action, abs(pos.position), account=app_ib.wrapper.accounts[0])
app_ib.placeOrder(pos.contract, close_order)
logger.info(f"Closed positions for outdated contract month {pos.contract.lastTradeDateOrContractMonth}")
# Open positions only for the difference between webhook and IB TWS positions
open_order_quantity = position_size - sum(pos.position for pos in positions_in_correct_month)
if open_order_quantity != 0:
open_order = MarketOrder("SELL" if open_order_quantity < 0 else "BUY", abs(open_order_quantity), account=app_ib.wrapper.accounts[0])
app_ib.placeOrder(correct_contract, open_order)
logger.info(f"Opened positions for the difference: {open_order_quantity} contracts of {ib_ticker} with contract month {current_contract_month}")
else:
logger.info(f"Contract month rollover check completed: Positions in IB TWS are using the correct contract month {current_contract_month}")
# Adjust Positions if Needed: Adjust positions to match the webhook
while True:
positions = await app_ib.reqPositions() # Use reqPositions to get real-time positions
if not positions:
logger.error("No positions retrieved from IB TWS API.")
return response.json({"status": "error", "message": "Failed to retrieve positions from IB TWS API."}, status=400)
current_position = sum(pos.position for pos in positions if pos.contract.symbol == ib_ticker)
ticker_positions = {pos.contract.symbol: pos.position for pos in positions}
logger.info(f"Current Positions: {ticker_positions}")
if current_position != position_size:
adjustment_quantity = position_size - current_position
adjustment_action = "SELL" if adjustment_quantity < 0 else "BUY"
adjustment_order = MarketOrder(adjustment_action, abs(adjustment_quantity), account=app_ib.wrapper.accounts[0])
logger.info(f"Adjusting Position: {adjustment_action} {abs(adjustment_quantity)} contracts of {ib_ticker}")
app_ib.placeOrder(correct_contract, adjustment_order)
logger.info(f"Position adjusted for {ib_ticker}: Before adjustment: {current_position}, After adjustment: {position_size}")
else:
logger.info(f"Position check completed: Positions in IB TWS match the positions from the webhook for contract month {current_contract_month}")
break
return response.json({"status": "success", "message": "Order placed and position adjusted if needed"})
except InvalidUsage as e:
logger.error(f"Invalid JSON received: {e}")
return response.json({"status": "error", "message": "Invalid JSON format"}, status=400)
except Exception as e:
logger.error(f"Error adjusting positions: {e}")
return response.json({"status": "error", "message": f"Failed to adjust positions: {str(e)}"}, status=500)
return response.json({"status": "error", "message": "Invalid request method"}, status=405)
if __name__ == '__main__':
try:
# Connect to IB on init
logger.info("Connecting to IB...")
app_ib.connect(HOST, PORT, clientId=0) # Using clientId=0 as Master Client
logger.info("Successfully Connected to IB")
# Set event handlers
set_event_handlers()
# Start the periodic update loop
asyncio.ensure_future(periodic_update())
app.run(port=8080)
except Exception as e:
logger.error(f"Failed to start the application: {e}")

View File

@@ -0,0 +1,105 @@
from datetime import datetime, timedelta
from ib_insync import Contract
from logger import LOGGER as log
def get_next_contract_month(ticker: str, offset=0, check_rollover=False) -> str:
"""Returns the next contract month in 'YYYYMM' format based on the ticker and specified conditions."""
now = datetime.now()
def next_quarter_month(date, offset=0):
"""Get the next quarter month (March, June, September, December) with an optional offset."""
quarter_months = [3, 6, 9, 12]
month = date.month
year = date.year
# Find the next quarter month
next_month = min((m for m in quarter_months if m > month), default=quarter_months[0])
if next_month <= month:
year += 1
next_month_index = (quarter_months.index(next_month) + offset) % len(quarter_months)
next_month = quarter_months[next_month_index]
return year, next_month
def get_monday_before_second_friday(year, month):
"""Get the Monday before the second Friday of the given month and year."""
first_day = datetime(year, month, 1)
first_friday = first_day + timedelta(days=(4 - first_day.weekday() + 7) % 7) # First Friday
second_friday = first_friday + timedelta(days=7)
return second_friday - timedelta(days=second_friday.weekday() + 7)
def get_monday_before_third_friday(year, month):
"""Get the Monday before the third Friday of the given month and year."""
first_day = datetime(year, month, 1)
first_friday = first_day + timedelta(days=(4 - first_day.weekday() + 7) % 7) # First Friday
third_friday = first_friday + timedelta(days=14)
return third_friday - timedelta(days=third_friday.weekday() + 7)
def get_last_monday_before_second_last_trading_day(year, month):
"""Get the last Monday before the second last trading day of the given month and year."""
last_day = datetime(year, month + 1, 1) - timedelta(days=1)
second_last_trading_day = last_day
while second_last_trading_day.weekday() in (5, 6): # Skip weekends
second_last_trading_day -= timedelta(days=1)
second_last_trading_day -= timedelta(days=1)
while second_last_trading_day.weekday() in (5, 6): # Skip weekends
second_last_trading_day -= timedelta(days=1)
return second_last_trading_day - timedelta(days=second_last_trading_day.weekday() + 1)
if ticker in ["ES", "MES", "NQ", "MNQ"]:
year, month = next_quarter_month(now)
monday_before_third_friday = get_monday_before_third_friday(year, month)
if now >= monday_before_third_friday:
year, month = next_quarter_month(datetime(year, month, 1), 1)
if check_rollover:
return True # Indicate rollover is needed
return f"{year}{month:02d}"
elif ticker in ["TOPX", "MNTPX"]:
year, month = next_quarter_month(now)
monday_before_second_friday = get_monday_before_second_friday(year, month)
if now >= monday_before_second_friday:
year, month = next_quarter_month(datetime(year, month, 1), 1)
if check_rollover:
return True # Indicate rollover is needed
return f"{year}{month:02d}"
elif ticker in ["HSI", "MHI"]:
year, month = next_quarter_month(now)
last_monday = get_last_monday_before_second_last_trading_day(year, month)
if now >= last_monday:
year, month = next_quarter_month(datetime(year, month, 1), 1)
if check_rollover:
return True # Indicate rollover is needed
return f"{year}{month:02d}"
else:
log.error(f"Invalid ticker: {ticker}. Please check the alert message.")
return None
def contract_type_check(ticker: str, contract_month=None) -> Contract:
contract = Contract()
contract.symbol = ticker
if not contract_month:
contract_month = get_next_contract_month(ticker)
if ticker == "SPY":
contract.secType = "STK"
contract.currency = "USD"
contract.exchange = "ARCA"
elif ticker.startswith("ETH"):
contract.secType = "CRYPTO"
contract.currency = "USD"
contract.exchange = "PAXOS"
elif ticker.startswith("EUR"):
contract.secType = "CASH"
contract.currency = "USD"
contract.exchange = "IDEALPRO"
elif ticker in ["ES", "MES", "NQ", "MNQ", "HSI", "MHI", "TOPX", "MNTPX"]:
contract.secType = "FUT"
contract.currency = "USD" if ticker in ["ES", "MES", "NQ", "MNQ"] else "HKD" if ticker in ["HSI", "MHI"] else "JPY"
contract.exchange = "CME" if ticker in ["ES", "MES", "NQ", "MNQ"] else "HKFE" if ticker in ["HSI", "MHI"] else "OSE"
contract.lastTradeDateOrContractMonth = contract_month
else:
log.error(f"Invalid ticker: {ticker}. Please check the alert message.")
return None
return contract

View File

@@ -0,0 +1,24 @@
import logging
# Create and configure logger
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.INFO)
# Create console handler and set level to INFO
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
# Create file handler and set level to INFO
fh = logging.FileHandler('app.log')
fh.setLevel(logging.INFO)
# Create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# Add formatter to handlers
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# Add handlers to logger
LOGGER.addHandler(ch)
LOGGER.addHandler(fh)

View File

@@ -0,0 +1,41 @@
---
tags: trading view, IB
---
# NOTES
```markdown
hello, 想請問搵你代寫 python 點收費?唔該
要求功能:
由 TradingView Webhook 轉成 Interative Broker TWS API 落 order 然後收 order confirmation, 跟住 keep 住 request and receive portfolio positions 去做 verifications (FYI 目前已有 script, 成功做到 convert from webhook to order placing, 但唔知點解做唔到 interact with IB TWS API)
因為呢度 send 唔到 link, 請參考 GitHub
1. TWS-orders-placement-via-Tradinview-webhooks
2. ib_insync
```
> 用 TWS-orders-placement-via-Tradinview-webhooks 嘅 template
> 然後再用 copilot 嚟幫我改做我嘅要求,已成功 place order
> 但未能收到 IB TWS API 嘅 order confirmation 嚟俾個 script run 埋下半 part
> 即係幫我 verify IB current positions 係咪等於我 webhook 個 new positions
> 我可以俾晒手頭上有嘅嘢俾你,你睇完先報價都冇問題,
> 但係我唔肯定係關 script 事定我自己未 install/setup 好所需要嘅嘢
hello, 想請問搵你代寫 python 點收費?唔該
要求功能:
1. 由 TradingView Webhook 轉成 Interative Broker TWS API 落 order
2. 然後收 order confirmation
3. 跟住 keep 住 request and receive portfolio positions 去做 verifications
4. FYI 目前已有 script, 成功做到 convert from webhook to order placing, 但唔知點解做唔到 interact with IB TWS API
因為呢度 send 唔到 link, 請參考 GitHub
1. TWS-orders-placement-via-Tradinview-webhooks
1. [https://github.com/EconLQ/TWS-orders-placement-via-Tradinview-webhooks](https://github.com/EconLQ/TWS-orders-placement-via-Tradinview-webhooks)
2. ib_insync(archived)
1. [https://github.com/erdewit/ib_insync](https://github.com/erdewit/ib_insync)