├── .gitignore
├── README.md
├── Untitled.ipynb
├── capturas
└── ejemplo.png
└── funciones.ipynb
/.gitignore:
--------------------------------------------------------------------------------
1 | 2019-12
2 | 2020-02
3 | Bonos.ipynb
4 | cookies.jar
5 | .ipynb_checkpoints
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # rodi_python
2 |
3 | Es un conjunto de funciones que permiten implementar una *Planilla Ford T* usando [https://jupyter.org](JupyterLab).
4 | También contiene funciones para obtener datos de *Rodi*.
5 |
6 | Sobre la *Planilla Ford T*: es la denominación que le puso Francisco Mancuso a su planilla básica (básica en comparación con la de @gcutte) para operar opciones [https://www.youtube.com/watch?v=oArjAhDeRaw](https://www.youtube.com/watch?v=oArjAhDeRaw).
7 |
8 | ## Modo de uso
9 |
10 | Aquellos entendidos en Python pueden usar las funciones diréctamente desde línea de comandos,
11 | o bien usarlas desde JupyterLab.
12 |
13 | ## Desde JupyterLab
14 |
15 | 1. Instalar JupyterLab.
16 | 2. Clonar este repositorio, por ej. en /home/leonardo/rodi_python o c:\rodi_python.
17 | 3. Posicionarse en el directorio anteriormente clonado.
18 | 4. ejecutar JupyterLab, en Linux `jupyterlab`. Se abrirá el navegador web apuntando a `http://localhost:8888/lab`.
19 |
20 | ### Acceso a datos en tiempo real
21 |
22 | Crear el archivo `bonos.ipynb` con el siguiente contenido:
23 |
24 | ```
25 | %run 'funciones.ipynb'
26 | import time
27 | from IPython.display import clear_output, display
28 | login_rodi("usuario_rodi", "password_rodi")
29 | while True:
30 | d=datapack()
31 | # Vencimiento 1: CI, 3: 48hs
32 | af20_ci=getRealtimeData(d['d']['aTabla'], "AF20", 1)["PrecioUltimo"]
33 | af20_48=getRealtimeData(d['d']['aTabla'], "AF20", 3)["PrecioUltimo"]
34 | ay24_ci=getRealtimeData(d['d']['aTabla'], "AY24", 1)["PrecioUltimo"]
35 | ay24_48=getRealtimeData(d['d']['aTabla'], "AY24", 3)["PrecioUltimo"]
36 | #ao20_ci=getRealtimeData(d['d']['aTabla'], "AO20", 1)["PrecioUltimo"]
37 | ao20_48=getRealtimeData(d['d']['aTabla'], "AO20", 3)["PrecioUltimo"]
38 | clear_output(wait=True)
39 | print("AF20: " + str(af20_48))
40 | print("AY24: " + str(ay24_48))
41 | print("AO20: " + str(ao20_48))
42 | print("AY24/AO20: " + str(ay24_48/ao20_48))
43 | print(8250*ay24_48/100/ao20_48*100)
44 | # debajo de 0.90 me conviene vender el AO20 y comprar AY24
45 | # arriba de 0.90 me conviene vender el AY24 y comprar AO20
46 | time.sleep(5)
47 | ```
48 |
49 | ### Planilla Ford T
50 |
51 | En forma similar a la planilla *Ford T* de Francisco Mancuso desarrollé esta librería, que permite cargar
52 | los datos de los trades en formato *JSON*.
53 |
54 |
55 | En el mismo directorio que el archivo `funciones.json` crear el siguiente archivo dentro de *JupyterLab*:
56 |
57 | ```
58 | %run 'funciones.ipynb'
59 |
60 | current=120
61 | trades=[
62 | {"date": "2019-12-19","type": "STOCK", "price": 108, "qty": 2400},
63 | {"date": "2019-12-19","type": "CALL", "base": 102, "price": 19.00, "qty": -24},
64 | {"date": "2019-12-19","type": "CALL", "base": 120, "price": 9.50, "qty": -100},
65 | # ideas
66 | ]
67 |
68 | getResults(trades)
69 | ```
70 |
71 | Debería quedar así:
72 |
73 | 
74 |
--------------------------------------------------------------------------------
/Untitled.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 5,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "name": "stdout",
10 | "output_type": "stream",
11 | "text": [
12 | "Acciones: 2400\n"
13 | ]
14 | },
15 | {
16 | "data": {
17 | "text/html": [
18 | "
| Precio | Valor | Calls: -24 | Puts: 0 |
\n",
48 | " \n",
49 | " 0 | \n",
50 | " 90.00 | \n",
51 | " 32400.00 | \n",
52 | " 0 | \n",
53 | " 0 | \n",
54 | "
\n",
55 | " \n",
56 | " 1 | \n",
57 | " 95.00 | \n",
58 | " 44400.00 | \n",
59 | " 0 | \n",
60 | " 0 | \n",
61 | "
\n",
62 | " \n",
63 | " 2 | \n",
64 | " 100.00 | \n",
65 | " 56400.00 | \n",
66 | " 0 | \n",
67 | " 0 | \n",
68 | "
\n",
69 | " \n",
70 | " 3 | \n",
71 | " 102.00 | \n",
72 | " 61200.00 | \n",
73 | " -24 | \n",
74 | " 0 | \n",
75 | "
\n",
76 | " \n",
77 | " 4 | \n",
78 | " 105.00 | \n",
79 | " 61200.00 | \n",
80 | " 0 | \n",
81 | " 0 | \n",
82 | "
\n",
83 | " \n",
84 | " 5 | \n",
85 | " 108.00 | \n",
86 | " 61200.00 | \n",
87 | " 0 | \n",
88 | " 0 | \n",
89 | "
\n",
90 | " \n",
91 | " 6 | \n",
92 | " 110.00 | \n",
93 | " 61200.00 | \n",
94 | " 0 | \n",
95 | " 0 | \n",
96 | "
\n",
97 | " \n",
98 | " 7 | \n",
99 | " 115.00 | \n",
100 | " 61200.00 | \n",
101 | " 0 | \n",
102 | " 0 | \n",
103 | "
\n",
104 | " \n",
105 | " 8 | \n",
106 | " 120.00 | \n",
107 | " 61200.00 | \n",
108 | " -100 | \n",
109 | " 0 | \n",
110 | "
\n",
111 | " \n",
112 | " 9 | \n",
113 | " 125.00 | \n",
114 | " 11200.00 | \n",
115 | " 0 | \n",
116 | " 0 | \n",
117 | "
\n",
118 | " \n",
119 | " 10 | \n",
120 | " 130.00 | \n",
121 | " -38800.00 | \n",
122 | " 0 | \n",
123 | " 0 | \n",
124 | "
\n",
125 | " \n",
126 | " 11 | \n",
127 | " 135.00 | \n",
128 | " -88800.00 | \n",
129 | " 100 | \n",
130 | " 0 | \n",
131 | "
\n",
132 | " \n",
133 | " 12 | \n",
134 | " 140.00 | \n",
135 | " -88800.00 | \n",
136 | " 0 | \n",
137 | " 0 | \n",
138 | "
\n",
139 | " \n",
140 | " 13 | \n",
141 | " 145.00 | \n",
142 | " -88800.00 | \n",
143 | " 0 | \n",
144 | " 0 | \n",
145 | "
\n",
146 | "
"
147 | ],
148 | "text/plain": [
149 | ""
150 | ]
151 | },
152 | "execution_count": 5,
153 | "metadata": {},
154 | "output_type": "execute_result"
155 | }
156 | ],
157 | "source": [
158 | "%run 'funciones.ipynb'\n",
159 | "\n",
160 | "current=120\n",
161 | "trades=[\n",
162 | " {\"date\": \"2019-12-19\",\"type\": \"STOCK\", \"price\": 108, \"qty\": 2400}, \n",
163 | " {\"date\": \"2019-12-19\",\"type\": \"CALL\", \"base\": 102, \"price\": 19.00, \"qty\": -24}, \n",
164 | " {\"date\": \"2019-12-19\",\"type\": \"CALL\", \"base\": 120, \"price\": 9.50, \"qty\": -100}, \n",
165 | " {\"date\": \"2019-12-19\",\"type\": \"CALL\", \"base\": 135, \"price\": 6.50, \"qty\": 100}, \n",
166 | " # ideas\n",
167 | "]\n",
168 | "\n",
169 | "getResults(trades)"
170 | ]
171 | }
172 | ],
173 | "metadata": {
174 | "kernelspec": {
175 | "display_name": "Python 3",
176 | "language": "python",
177 | "name": "python3"
178 | },
179 | "language_info": {
180 | "codemirror_mode": {
181 | "name": "ipython",
182 | "version": 2
183 | },
184 | "file_extension": ".py",
185 | "mimetype": "text/x-python",
186 | "name": "python",
187 | "nbconvert_exporter": "python",
188 | "pygments_lexer": "ipython2",
189 | "version": "2.7.12"
190 | }
191 | },
192 | "nbformat": 4,
193 | "nbformat_minor": 2
194 | }
195 |
--------------------------------------------------------------------------------
/capturas/ejemplo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leonardorame/rodi_python/ce50a7b907a87e343d6e2c5b4691680100c1fa8e/capturas/ejemplo.png
--------------------------------------------------------------------------------
/funciones.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 5,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import numpy\n",
10 | "import pandas as pd\n",
11 | "import pandas.io.formats.style\n",
12 | "from decimal import Decimal\n",
13 | "from ipywidgets import HBox\n",
14 | "\n",
15 | "def color_negative_red(value):\n",
16 | " if float(value) < 0:\n",
17 | " color = 'red'\n",
18 | " elif float(value) > 0:\n",
19 | " color = 'green'\n",
20 | " else:\n",
21 | " color = 'black'\n",
22 | "\n",
23 | " return 'color: %s' % color\n",
24 | "\n",
25 | "def getResults(trades):\n",
26 | " rango = numpy.arange(current - (current / 4), current + (current / 4), 5)\n",
27 | " rango = list(rango)\n",
28 | " for trade in trades:\n",
29 | " if trade.has_key(\"base\"):\n",
30 | " rango.append(trade[\"base\"])\n",
31 | " if trade[\"type\"] == \"STOCK\":\n",
32 | " rango.append(trade[\"price\"]) \n",
33 | " rango = list(set(rango))\n",
34 | " rango.sort()\n",
35 | " tabla = []\n",
36 | " total_calls = 0\n",
37 | " total_puts = 0\n",
38 | " total_stocks = 0\n",
39 | " for i in rango:\n",
40 | " res = 0\n",
41 | " registro = {\"indice\": i, \"valor\": 0.0, \"calls\": 0, \"puts\": 0}\n",
42 | " for trade in trades:\n",
43 | " # acciones\n",
44 | " if trade[\"type\"] == \"STOCK\":\n",
45 | " dif = (i - trade[\"price\"])\n",
46 | "\n",
47 | " if(trade[\"price\"] == i):\n",
48 | " total_stocks = total_stocks + trade[\"qty\"]\n",
49 | " res = res + (trade[\"qty\"]*dif) \n",
50 | " registro[\"valor\"] = round(res, 2)\n",
51 | " # opciones\n",
52 | " if trade.has_key(\"base\"):\n",
53 | " dif = (i - trade[\"base\"])\n",
54 | " if trade[\"type\"] == \"CALL\": \n",
55 | " if(trade[\"base\"] == i):\n",
56 | " registro[\"calls\"] = registro[\"calls\"] + trade[\"qty\"]\n",
57 | " total_calls = total_calls + trade[\"qty\"]\n",
58 | " if trade[\"base\"] > i:\n",
59 | " res = res + (trade[\"price\"]*trade[\"qty\"]*100*-1)\n",
60 | " else:\n",
61 | " res = res + ((dif-trade[\"price\"])*trade[\"qty\"]*100)\n",
62 | " if trade[\"type\"] == \"PUT\":\n",
63 | " if(trade[\"base\"] == i):\n",
64 | " registro[\"puts\"] = registro[\"puts\"] + trade[\"qty\"]\n",
65 | " total_puts = total_puts + trade[\"qty\"]\n",
66 | " if trade[\"base\"] > i:\n",
67 | " res = res - ((dif + trade[\"price\"])*trade[\"qty\"]*100)\n",
68 | " else:\n",
69 | " res = res - (trade[\"price\"]*trade[\"qty\"]*100)\n",
70 | " registro[\"valor\"] = round(res, 2)\n",
71 | " tabla.append([format(registro[\"indice\"], '0.2f'), format(registro[\"valor\"], '0.2f'), registro[\"calls\"], registro[\"puts\"]])\n",
72 | " \n",
73 | " print( \"Acciones: {}\".format(total_stocks))\n",
74 | " calls = \"Calls: {}\".format(total_calls)\n",
75 | " puts = \"Puts: {}\".format(total_puts)\n",
76 | " df = pd.DataFrame(tabla, columns=[\"Precio\", \"Valor\", calls, puts])\n",
77 | " df = df.style.applymap(color_negative_red, subset=[\"Valor\"])\n",
78 | " return df\n",
79 | "\n",
80 | "def login_rodi(username, password):\n",
81 | " import requests\n",
82 | " import pickle\n",
83 | " import codecs\n",
84 | " from bs4 import BeautifulSoup\n",
85 | "\n",
86 | " # with open('cookies.jar', 'rb') as f:\n",
87 | " # cookies = pickle.load(f)\n",
88 | " # print(cookies)\n",
89 | "\n",
90 | " URL=\"https://rodi.sba.com.ar/Vistas/Login.aspx\"\n",
91 | " URLGetEspecies=\"https://rodi.sba.com.ar/Vistas/PanelPersonal.aspx/GetEspecies\"\n",
92 | " URLDataPack=\"https://rodi.sba.com.ar/Vistas/PanelPersonal.aspx/GetDataPack\"\n",
93 | " headers={\n",
94 | " \"User-Agent\":\"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36\",\n",
95 | " \"Referer\": \"https://rodi.sba.com.ar/Vistas/PanelPersonal.aspx\",\n",
96 | " \"X-Request-Width\": \"XMLHttpRequest\",\n",
97 | " \"Host\": \"rodi.sba.com.ar\"\n",
98 | " } \n",
99 | "\n",
100 | " s=requests.Session()\n",
101 | " s.headers.update(headers)\n",
102 | " r=s.get(URL)\n",
103 | " soup=BeautifulSoup(r.content, \"lxml\")\n",
104 | "\n",
105 | " VIEWSTATE=soup.find(id=\"__VIEWSTATE\")['value']\n",
106 | " VIEWSTATEGENERATOR=soup.find(id=\"__VIEWSTATEGENERATOR\")['value']\n",
107 | " EVENTVALIDATION=soup.find(id=\"__EVENTVALIDATION\")['value']\n",
108 | "\n",
109 | " login_data={\"__LASTFOCUS\":\"\",\n",
110 | " \"__EVENTTARGET\":\"\",\n",
111 | " \"__EVENTARGUMENT\":\"\",\n",
112 | " \"__VIEWSTATE\":VIEWSTATE,\n",
113 | " \"__VIEWSTATEGENERATOR\":VIEWSTATEGENERATOR,\n",
114 | " \"__EVENTVALIDATION\":EVENTVALIDATION,\n",
115 | " \"ctl00$ContentPlaceHolder1$luLogin$txtUsuario\": username,\n",
116 | " \"ctl00$ContentPlaceHolder1$luLogin$txtClave\":password,\n",
117 | " \"ctl00$ContentPlaceHolder1$luLogin$ctl07\":\"Ingresar\"}\n",
118 | "\n",
119 | " r=s.post(URL, data=login_data)\n",
120 | "\n",
121 | " # luego se llama al HTML de DataPack, sin esto\n",
122 | " # las sucesivas llamadas a DataPack no traen el JSON\n",
123 | " r=s.get(URLDataPack)\n",
124 | "\n",
125 | " with open('cookies.jar', 'wb') as f:\n",
126 | " pickle.dump(s.cookies, f)\n",
127 | "\n",
128 | " print(\"cookies guardadas en archivo cookies.jar\")\n",
129 | " return\n",
130 | " \n",
131 | "def datapack():\n",
132 | " import requests\n",
133 | " import pickle\n",
134 | " import json\n",
135 | " from bs4 import BeautifulSoup\n",
136 | "\n",
137 | " URLDataPack=\"https://rodi.sba.com.ar/Vistas/PanelPersonal.aspx/GetDataPack\"\n",
138 | " headers={\n",
139 | " \"User-Agent\":\"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36\",\n",
140 | " \"Referer\": \"https://rodi.sba.com.ar/Vistas/PanelPersonal.aspx\",\n",
141 | " \"X-Request-Width\": \"XMLHttpRequest\",\n",
142 | " \"Host\": \"rodi.sba.com.ar\"\n",
143 | " }\n",
144 | "\n",
145 | " s=requests.Session()\n",
146 | "\n",
147 | " with open('cookies.jar', 'rb') as f:\n",
148 | " s.cookies.update(pickle.load(f))\n",
149 | "\n",
150 | " # los tickers tienen que estar cargados previamente en RODI, de lo contrario esto no funciona.\n",
151 | " params={'obEstadoTabla' : {\"TablaNombre\":\"tbEspecies\",\"FiltroEspecies\":\"AF20_1#AF20_3#AO20_1#AO20_3#AY24_1#AY24_3#GFGC102.OC_0#GFGC105.OC_0#GFGC111.DI_0#GFGC111.OC_0#GFGC120.OC_0#GFGC132.DI_0#GFGC150.DI_0#GFGC63.0OC_0#GFGC75.0OC_0#GFGC80.0OC_0#GFGC87.0OC_0#GFGC90.0OC_0#GFGC93.0OC_0#GFGC99.0OC_0#GFGV102.DI_0#GFGV60.0OC_0#GFGV63.0OC_0#GFGV80.0OC_0#GFGV90.0DI_0#GFGV93.0OC_0#GFGV99.0OC_0#GGAL_3#GFGC102.DI_0\",\"PagActualNro\":\"1\",\"FilasxPagina\":50}}\n",
152 | " # luego al JSON\n",
153 | " r=s.post(URLDataPack, json=params, headers=headers)\n",
154 | "\n",
155 | " with open('cookies.jar', 'wb') as f:\n",
156 | " pickle.dump(s.cookies, f)\n",
157 | " return json.loads(r.text)\n",
158 | " \n",
159 | "def getRealtimeData(aData, aTicker, aVencimiento):\n",
160 | " for item in aData:\n",
161 | " if (item[\"Simbolo\"] == aTicker) and (item[\"VencimientoID\"] == aVencimiento):\n",
162 | " return item\n"
163 | ]
164 | },
165 | {
166 | "cell_type": "code",
167 | "execution_count": null,
168 | "metadata": {},
169 | "outputs": [],
170 | "source": []
171 | }
172 | ],
173 | "metadata": {
174 | "kernelspec": {
175 | "display_name": "Python 3",
176 | "language": "python",
177 | "name": "python3"
178 | },
179 | "language_info": {
180 | "codemirror_mode": {
181 | "name": "ipython",
182 | "version": 2
183 | },
184 | "file_extension": ".py",
185 | "mimetype": "text/x-python",
186 | "name": "python",
187 | "nbconvert_exporter": "python",
188 | "pygments_lexer": "ipython2",
189 | "version": "2.7.12"
190 | }
191 | },
192 | "nbformat": 4,
193 | "nbformat_minor": 4
194 | }
195 |
--------------------------------------------------------------------------------